Salome HOME
Copyright update 2022
[plugins/ghs3dplugin.git] / src / GHS3DPlugin / GHS3DPlugin_Hypothesis.cxx
1 // Copyright (C) 2004-2022  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 //=============================================================================
21 // File      : GHS3DPlugin_Hypothesis.cxx
22 // Created   : Wed Apr  2 12:36:29 2008
23 // Author    : Edward AGAPOV (eap)
24 //=============================================================================
25 //
26 #include "GHS3DPlugin_Hypothesis.hxx"
27
28 #include <Basics_DirUtils.hxx>
29 #include <SMESHDS_Mesh.hxx>
30 #include <SMESH_File.hxx>
31
32 #include <TCollection_AsciiString.hxx>
33
34 #ifdef WIN32
35 #include <process.h>
36 #define getpid _getpid
37 #endif
38
39 using namespace std;
40
41 namespace
42 {
43   struct GET_DEFAULT // struct used to get default value from GetOptionValue()
44   {
45     bool isDefault;
46     operator bool* () { return &isDefault; }
47   };
48 }
49
50 //=======================================================================
51 //function : GHS3DPlugin_Hypothesis
52 //=======================================================================
53
54 GHS3DPlugin_Hypothesis::GHS3DPlugin_Hypothesis(int hypId, SMESH_Gen * gen)
55   : SMESH_Hypothesis(hypId, gen),
56     myToMeshHoles(DefaultMeshHoles()),
57     myToMakeGroupsOfDomains(DefaultToMakeGroupsOfDomains()),
58     myMaximumMemory(-1),
59     myInitialMemory(-1),
60     myOptimizationLevel(DefaultOptimizationLevel()),
61     myKeepFiles(DefaultKeepFiles()),
62     myWorkingDirectory(DefaultWorkingDirectory()),
63     myVerboseLevel(DefaultVerboseLevel()),
64     myToCreateNewNodes(DefaultToCreateNewNodes()),
65     myToUseBoundaryRecoveryVersion(DefaultToUseBoundaryRecoveryVersion()),
66     myToUseFemCorrection(DefaultToUseFEMCorrection()),
67     myToRemoveCentralPoint(DefaultToRemoveCentralPoint()),
68     myLogInStandardOutput(DefaultStandardOutputLog()),
69     myRemoveLogOnSuccess( DefaultRemoveLogOnSuccess() ),
70     myGradation(DefaultGradation()),
71     myUseVolumeProximity(DefaultUseVolumeProximity()),
72     myNbVolumeProximityLayers(DefaultNbVolumeProximityLayers()),
73     myMinSize(0),
74     myMinSizeDefault(0),
75     myMaxSize(0),
76     myMaxSizeDefault(0)
77 {
78   _name = GetHypType();
79   _param_algo_dim = 3;
80
81   const char* boolOptionNames[] = { "no_initial_central_point",                          // no
82                                     "force_max_size",                                    // no
83                                     "apply_gradation_on_skin_vertex_sizes",              // yes
84                                     "optimise_worst_elements",                           // no
85                                     "force_output_quadratic_mesh",                       // no
86                                     "rectify_jacobian",                                  // yes
87                                     "jacobian_rectification_respect_input_surface_mesh", // yes
88                                     "" // mark of end
89   };
90   const char* intOptionNames[] = { "max_number_of_errors_printed", // 1
91                                    "max_number_of_threads",        // 4
92                                    "" // mark of end
93   };
94   const char* doubleOptionNames[] = { "target_quality",  // 0
95                                       "sliver_angle",    // 5
96                                       "" // mark of end
97   };
98   const char* charOptionNames[] = { "pthreads_mode",                    // ""
99                                     "boundary_regeneration",            // standard
100                                     "split_overconstrained_tetrahedra", // no
101                                     "" // mark of end
102   };
103
104   int i = 0;
105   while (boolOptionNames[i][0])
106   {
107     _boolOptions.insert( boolOptionNames[i] );
108     _option2value[boolOptionNames[i++]].clear();
109   }
110   i = 0;
111   while (intOptionNames[i][0])
112     _option2value[intOptionNames[i++]].clear();
113   
114   i = 0;
115   while (doubleOptionNames[i][0]) {
116     _doubleOptions.insert(doubleOptionNames[i]);
117     _option2value[doubleOptionNames[i++]].clear();
118   }
119   i = 0;
120   while (charOptionNames[i][0]) {
121     _charOptions.insert(charOptionNames[i]);
122     _option2value[charOptionNames[i++]].clear();
123   }
124
125   // default values to be used while MG meshing
126
127   _defaultOptionValues["no_initial_central_point"                         ] = "no";
128   _defaultOptionValues["force_max_size"                                   ] = "no";
129   _defaultOptionValues["apply_gradation_on_skin_vertex_sizes"             ] = "yes";
130   _defaultOptionValues["optimise_worst_elements"                          ] = "no";
131   _defaultOptionValues["force_output_quadratic_mesh"                      ] = "no";
132   _defaultOptionValues["rectify_jacobian"                                 ] = "yes";
133   _defaultOptionValues["jacobian_rectification_respect_input_surface_mesh"] = "yes";
134   _defaultOptionValues["max_number_of_errors_printed"                     ] = "1";
135   _defaultOptionValues["max_number_of_threads"                            ] = "4";
136   _defaultOptionValues["target_quality"                                   ] = "";//NoValue();
137   _defaultOptionValues["sliver_angle"                                     ] = "5";
138   _defaultOptionValues["pthreads_mode"                                    ] = "";//NoValue();
139   _defaultOptionValues["boundary_regeneration"                            ] = "standard";
140   _defaultOptionValues["split_overconstrained_tetrahedra"                 ] = "no";
141
142 #ifdef _DEBUG_
143   // check validity of option names of _defaultOptionValues
144   TOptionValues::iterator n2v = _defaultOptionValues.begin();
145   for ( ; n2v != _defaultOptionValues.end(); ++n2v )
146     ASSERT( _option2value.count( n2v->first ));
147   ASSERT( _option2value.size() == _defaultOptionValues.size() );
148 #endif
149 }
150
151 //=======================================================================
152 //function : SetToMeshHoles
153 //=======================================================================
154
155 void GHS3DPlugin_Hypothesis::SetToMeshHoles(bool toMesh)
156 {
157   if ( myToMeshHoles != toMesh ) {
158     myToMeshHoles = toMesh;
159     NotifySubMeshesHypothesisModification();
160   }
161 }
162
163 //=======================================================================
164 //function : GetToMeshHoles
165 //=======================================================================
166
167 bool GHS3DPlugin_Hypothesis::GetToMeshHoles(bool checkFreeOption) const
168 {
169   if ( checkFreeOption )
170   {
171     std::string optionName = "components";
172     TOptionValues::const_iterator op_val = _customOption2value.find(optionName);
173     if ( op_val != _customOption2value.end())
174     {
175       if ( op_val->second.find("all"))
176         return true;
177       if ( op_val->second.find("outside_components"))
178         return false;
179     }
180   }
181   return myToMeshHoles;
182 }
183
184 //=======================================================================
185 //function : SetToMakeGroupsOfDomains
186 //=======================================================================
187
188 void GHS3DPlugin_Hypothesis::SetToMakeGroupsOfDomains(bool toMakeGroups)
189 {
190   if ( myToMakeGroupsOfDomains != toMakeGroups ) {
191     myToMakeGroupsOfDomains = toMakeGroups;
192     NotifySubMeshesHypothesisModification();
193   }
194 }
195
196 //=======================================================================
197 //function : GetToMakeGroupsOfDomains
198 //=======================================================================
199
200 bool GHS3DPlugin_Hypothesis::GetToMakeGroupsOfDomains() const
201 {
202   return myToMakeGroupsOfDomains;
203 }
204
205 //=======================================================================
206 //function : GetToMakeGroupsOfDomains
207 //=======================================================================
208
209 bool GHS3DPlugin_Hypothesis::GetToMakeGroupsOfDomains(const GHS3DPlugin_Hypothesis* hyp)
210 {
211   bool res;
212   if ( hyp ) res = /*hyp->GetToMeshHoles(true) &&*/ hyp->GetToMakeGroupsOfDomains();
213   else       res = /*DefaultMeshHoles()        &&*/ DefaultToMakeGroupsOfDomains();
214   return res;
215 }
216
217 //=======================================================================
218 //function : SetMaximumMemory
219 //=======================================================================
220
221 void GHS3DPlugin_Hypothesis::SetMaximumMemory(float MB)
222 {
223   if ( myMaximumMemory != MB ) {
224     myMaximumMemory = MB;
225     NotifySubMeshesHypothesisModification();
226   }
227 }
228
229 //=======================================================================
230 //function : GetMaximumMemory
231 //           * automatic memory adjustment mode. Default is zero
232 //=======================================================================
233
234 float GHS3DPlugin_Hypothesis::GetMaximumMemory() const
235 {
236   return myMaximumMemory;
237 }
238
239 //=======================================================================
240 //function : SetInitialMemory
241 //=======================================================================
242
243 void GHS3DPlugin_Hypothesis::SetInitialMemory(float MB)
244 {
245   if ( myInitialMemory != MB ) {
246     myInitialMemory = MB;
247     NotifySubMeshesHypothesisModification();
248   }
249 }
250
251 //=======================================================================
252 //function : GetInitialMemory
253 //=======================================================================
254
255 float GHS3DPlugin_Hypothesis::GetInitialMemory() const
256 {
257   return myInitialMemory;
258 }
259
260 //=======================================================================
261 //function : SetOptimizationLevel
262 //=======================================================================
263
264 void GHS3DPlugin_Hypothesis::SetOptimizationLevel(OptimizationLevel level)
265 {
266   if ( myOptimizationLevel != level ) {
267     myOptimizationLevel = level;
268     NotifySubMeshesHypothesisModification();
269   }
270 }
271
272 //=======================================================================
273 //function : GetOptimizationLevel
274 //=======================================================================
275
276 GHS3DPlugin_Hypothesis::OptimizationLevel GHS3DPlugin_Hypothesis::GetOptimizationLevel() const
277 {
278   return (OptimizationLevel) myOptimizationLevel;
279 }
280
281 //=======================================================================
282 //function : SetWorkingDirectory
283 //=======================================================================
284
285 void GHS3DPlugin_Hypothesis::SetWorkingDirectory(const std::string& path)
286 {
287   if ( myWorkingDirectory != path ) {
288     myWorkingDirectory = path;
289     NotifySubMeshesHypothesisModification();
290   }
291 }
292
293 //=======================================================================
294 //function : GetWorkingDirectory
295 //=======================================================================
296
297 std::string GHS3DPlugin_Hypothesis::GetWorkingDirectory() const
298 {
299   return myWorkingDirectory;
300 }
301
302 //=======================================================================
303 //function : SetKeepFiles
304 //=======================================================================
305
306 void GHS3DPlugin_Hypothesis::SetKeepFiles(bool toKeep)
307 {
308   if ( myKeepFiles != toKeep ) {
309     myKeepFiles = toKeep;
310     NotifySubMeshesHypothesisModification();
311   }
312 }
313
314 //=======================================================================
315 //function : GetKeepFiles
316 //=======================================================================
317
318 bool GHS3DPlugin_Hypothesis::GetKeepFiles() const
319 {
320   return myKeepFiles;
321 }
322
323 //=======================================================================
324 //function : SetVerboseLevel
325 //=======================================================================
326
327 void GHS3DPlugin_Hypothesis::SetVerboseLevel(short level)
328 {
329   if ( myVerboseLevel != level ) {
330     myVerboseLevel = level;
331     NotifySubMeshesHypothesisModification();
332   }
333 }
334
335 //=======================================================================
336 //function : GetVerboseLevel
337 //=======================================================================
338
339 short GHS3DPlugin_Hypothesis::GetVerboseLevel() const
340 {
341   return myVerboseLevel;
342 }
343
344 //=======================================================================
345 //function : SetToCreateNewNodes
346 //=======================================================================
347
348 void GHS3DPlugin_Hypothesis::SetToCreateNewNodes(bool toCreate)
349 {
350   if ( myToCreateNewNodes != toCreate ) {
351     myToCreateNewNodes = toCreate;
352     NotifySubMeshesHypothesisModification();
353   }
354 }
355
356 //=======================================================================
357 //function : GetToCreateNewNodes
358 //=======================================================================
359
360 bool GHS3DPlugin_Hypothesis::GetToCreateNewNodes() const
361 {
362   return myToCreateNewNodes;
363 }
364
365 //=======================================================================
366 //function : SetToUseBoundaryRecoveryVersion
367 //=======================================================================
368
369 void GHS3DPlugin_Hypothesis::SetToUseBoundaryRecoveryVersion(bool toUse)
370 {
371   if ( myToUseBoundaryRecoveryVersion != toUse ) {
372     myToUseBoundaryRecoveryVersion = toUse;
373     NotifySubMeshesHypothesisModification();
374   }
375 }
376
377 //=======================================================================
378 //function : GetToUseBoundaryRecoveryVersion
379 //=======================================================================
380
381 bool GHS3DPlugin_Hypothesis::GetToUseBoundaryRecoveryVersion() const
382 {
383   return myToUseBoundaryRecoveryVersion;
384 }
385
386 //=======================================================================
387 //function : SetFEMCorrection
388 //=======================================================================
389
390 void GHS3DPlugin_Hypothesis::SetFEMCorrection(bool toUseFem)
391 {
392   if ( myToUseFemCorrection != toUseFem ) {
393     myToUseFemCorrection = toUseFem;
394     NotifySubMeshesHypothesisModification();
395   }
396 }
397
398 //=======================================================================
399 //function : GetFEMCorrection
400 //=======================================================================
401
402 bool GHS3DPlugin_Hypothesis::GetFEMCorrection() const
403 {
404   return myToUseFemCorrection;
405 }
406
407 //=======================================================================
408 //function : SetToRemoveCentralPoint
409 //=======================================================================
410
411 void GHS3DPlugin_Hypothesis::SetToRemoveCentralPoint(bool toRemove)
412 {
413   SetOptionValue( "no_initial_central_point", toRemove ? "yes" : "no" );
414   myToRemoveCentralPoint = toRemove;
415 }
416
417 //=======================================================================
418 //function : GetToRemoveCentralPoint
419 //=======================================================================
420
421 bool GHS3DPlugin_Hypothesis::GetToRemoveCentralPoint() const
422 {
423   return myToRemoveCentralPoint;
424 }
425
426 //=======================================================================
427 //function : SetAdvancedOption
428 //=======================================================================
429
430 void GHS3DPlugin_Hypothesis::SetAdvancedOption(const std::string& option)
431 {
432   size_t wsPos = option.find(' ');
433   if ( wsPos == string::npos )
434   {
435     SetOptionValue( option, "" );
436   }
437   else
438   {
439     std::string opt( option, 0, wsPos );
440     std::string val( option, wsPos + 1 );
441     SetOptionValue( opt, val );
442   }
443 }
444
445 //=======================================================================
446 //function : GetAdvancedOption
447 //=======================================================================
448
449 std::string GHS3DPlugin_Hypothesis::GetAdvancedOption() const
450 {
451   SMESH_Comment txt;
452
453   TOptionValues::const_iterator o2v = _option2value.begin();
454   for ( ; o2v != _option2value.end(); ++o2v )
455     if ( !o2v->second.empty() )
456     {
457       if ( !txt.empty() )
458         txt << " ";
459       txt << o2v->first << " " << o2v->second;
460     }
461   for ( o2v = _customOption2value.begin(); o2v != _customOption2value.end(); ++o2v )
462   {
463     if ( !txt.empty() )
464       txt << " ";
465     txt << o2v->first << " " << o2v->second;
466   }
467   return txt;
468 }
469
470 //=======================================================================
471 //function : SetGradation
472 //=======================================================================
473
474 void GHS3DPlugin_Hypothesis::SetGradation(double gradation)
475 {
476   if ( myGradation != gradation ) {
477     myGradation = gradation;
478     NotifySubMeshesHypothesisModification();
479   }
480 }
481
482 //=======================================================================
483 //function : GetGradation
484 //=======================================================================
485
486 double GHS3DPlugin_Hypothesis::GetGradation() const
487 {
488   return myGradation;
489 }
490
491 //=============================================================================
492 void GHS3DPlugin_Hypothesis::SetMinSize(double theMinSize)
493 {
494   if ( theMinSize != myMinSize )
495   {
496     myMinSize = theMinSize;
497     NotifySubMeshesHypothesisModification();
498   }
499 }
500
501 //=============================================================================
502 void GHS3DPlugin_Hypothesis::SetMaxSize(double theMaxSize)
503 {
504   if ( theMaxSize != myMaxSize )
505   {
506     myMaxSize = theMaxSize;
507     NotifySubMeshesHypothesisModification();
508   }
509 }
510
511 //=============================================================================
512 void GHS3DPlugin_Hypothesis::SetUseVolumeProximity( bool toUse )
513 {
514   if ( myUseVolumeProximity != toUse )
515   {
516     myUseVolumeProximity = toUse;
517     NotifySubMeshesHypothesisModification();
518   }
519 }
520
521 //=============================================================================
522 void GHS3DPlugin_Hypothesis::SetNbVolumeProximityLayers( int nbLayers )
523 {
524   if ( myNbVolumeProximityLayers != nbLayers )
525   {
526     myNbVolumeProximityLayers = nbLayers;
527     NotifySubMeshesHypothesisModification();
528   }
529 }
530
531 //=======================================================================
532 //function : SetStandardOutputLog
533 //=======================================================================
534
535 void GHS3DPlugin_Hypothesis::SetStandardOutputLog(bool logInStandardOutput)
536 {
537   if ( myLogInStandardOutput != logInStandardOutput ) {
538     myLogInStandardOutput = logInStandardOutput;
539     NotifySubMeshesHypothesisModification();
540   }
541 }
542
543 //=======================================================================
544 //function : GetStandardOutputLog
545 //=======================================================================
546
547 bool GHS3DPlugin_Hypothesis::GetStandardOutputLog() const
548 {
549   return myLogInStandardOutput;
550 }
551
552 //=======================================================================
553 //function : SetRemoveLogOnSuccess
554 //=======================================================================
555
556 void GHS3DPlugin_Hypothesis::SetRemoveLogOnSuccess(bool removeLogOnSuccess)
557 {
558   if ( myRemoveLogOnSuccess != removeLogOnSuccess ) {
559     myRemoveLogOnSuccess = removeLogOnSuccess;
560     NotifySubMeshesHypothesisModification();
561   }
562 }
563
564 //=======================================================================
565 //function : GetRemoveLogOnSuccess
566 //=======================================================================
567
568 bool GHS3DPlugin_Hypothesis::GetRemoveLogOnSuccess() const
569 {
570   return myRemoveLogOnSuccess;
571 }
572
573 //=======================================================================
574 //function : SetEnforcedVertex
575 //=======================================================================
576
577 bool GHS3DPlugin_Hypothesis::SetEnforcedVertex(std::string theName,
578                                                std::string theEntry,
579                                                std::string theGroupName,
580                                                double      size,
581                                                double x, double y, double z,
582                                                bool        isCompound)
583 {
584   MESSAGE("GHS3DPlugin_Hypothesis::SetEnforcedVertex(\""<< theName << "\", \""<< theEntry << "\", \"" << theGroupName << "\", "
585                                                       << size << ", " << x << ", " << y << ", " << z  << ", "<< isCompound << ")");
586
587   bool toNotify = false;
588   bool toCreate = true;
589
590   TGHS3DEnforcedVertex *oldEnVertex;
591   TGHS3DEnforcedVertex *newEnfVertex = new TGHS3DEnforcedVertex();
592   newEnfVertex->name = theName;
593   newEnfVertex->geomEntry = theEntry;
594   newEnfVertex->coords.clear();
595   if (!isCompound) {
596     newEnfVertex->coords.push_back(x);
597     newEnfVertex->coords.push_back(y);
598     newEnfVertex->coords.push_back(z);
599   }
600   newEnfVertex->groupName = theGroupName;
601   newEnfVertex->size = size;
602   newEnfVertex->isCompound = isCompound;
603   
604   
605   // update _enfVertexList
606   TGHS3DEnforcedVertexList::iterator it = _enfVertexList.find(newEnfVertex);
607   if (it != _enfVertexList.end()) {
608     toCreate = false;
609     oldEnVertex = (*it);
610     MESSAGE("Enforced Vertex was found => Update");
611     if (oldEnVertex->name != theName) {
612       MESSAGE("Update name from \"" << oldEnVertex->name << "\" to \"" << theName << "\"");
613       oldEnVertex->name = theName;
614       toNotify = true;
615     }
616     if (oldEnVertex->groupName != theGroupName) {
617       MESSAGE("Update group name from \"" << oldEnVertex->groupName << "\" to \"" << theGroupName << "\"");
618       oldEnVertex->groupName = theGroupName;
619       toNotify = true;
620     }
621     if (oldEnVertex->size != size) {
622       MESSAGE("Update size from \"" << oldEnVertex->size << "\" to \"" << size << "\"");
623       oldEnVertex->size = size;
624       toNotify = true;
625     }
626     if (toNotify) {
627       // update map coords / enf vertex if needed
628       if (oldEnVertex->coords.size()) {
629         _coordsEnfVertexMap[oldEnVertex->coords] = oldEnVertex;
630         _enfVertexCoordsSizeList[oldEnVertex->coords] = size;
631       }
632
633       // update map geom entry / enf vertex if needed
634       if (oldEnVertex->geomEntry != "") {
635         _geomEntryEnfVertexMap[oldEnVertex->geomEntry] = oldEnVertex;
636         _enfVertexEntrySizeList[oldEnVertex->geomEntry] = size;
637       }
638     }
639   }
640
641 //   //////// CREATE ////////////
642   if (toCreate) {
643     toNotify = true;
644     MESSAGE("Creating new enforced vertex");
645     _enfVertexList.insert(newEnfVertex);
646     if (theEntry == "") {
647       _coordsEnfVertexMap[newEnfVertex->coords] = newEnfVertex;
648       _enfVertexCoordsSizeList[newEnfVertex->coords] = size;
649     }
650     else {
651       _geomEntryEnfVertexMap[newEnfVertex->geomEntry] = newEnfVertex;
652       _enfVertexEntrySizeList[newEnfVertex->geomEntry] = size;
653     }
654   }
655
656   if (toNotify)
657     NotifySubMeshesHypothesisModification();
658
659   MESSAGE("GHS3DPlugin_Hypothesis::SetEnforcedVertex END");
660   return toNotify;
661 }
662
663
664 //=======================================================================
665 //function : SetEnforcedMesh
666 //=======================================================================
667 bool GHS3DPlugin_Hypothesis::SetEnforcedMesh(SMESH_Mesh& theMesh, SMESH::ElementType elementType, std::string name, std::string entry, std::string groupName)
668 {
669   TIDSortedElemSet theElemSet;
670   SMDS_ElemIteratorPtr eIt = theMesh.GetMeshDS()->elementsIterator(SMDSAbs_ElementType(elementType));
671   while ( eIt->more() )
672     theElemSet.insert( eIt->next() );
673   MESSAGE("Add "<<theElemSet.size()<<" types["<<elementType<<"] from source mesh");
674   bool added = SetEnforcedElements( theElemSet, elementType, groupName);
675   if (added) {
676     TGHS3DEnforcedMesh* newEnfMesh = new TGHS3DEnforcedMesh();
677     newEnfMesh->persistID   = theMesh.GetMeshDS()->GetPersistentId();
678     newEnfMesh->name        = name;
679     newEnfMesh->entry       = entry;
680     newEnfMesh->elementType = elementType;
681     newEnfMesh->groupName   = groupName;
682     
683     TGHS3DEnforcedMeshList::iterator it = _enfMeshList.find(newEnfMesh);
684     if (it == _enfMeshList.end()) {
685       _entryEnfMeshMap[entry].insert(newEnfMesh);
686       _enfMeshList.insert(newEnfMesh);
687     }
688     else {
689       delete newEnfMesh;
690     }
691   }
692   return added;
693 }
694
695 //=======================================================================
696 //function : SetEnforcedGroup
697 //=======================================================================
698 bool GHS3DPlugin_Hypothesis::SetEnforcedGroup(const SMESHDS_Mesh* theMeshDS, SMESH::smIdType_array_var theIDs, SMESH::ElementType elementType, std::string name, std::string entry, std::string groupName)
699 {
700   MESSAGE("GHS3DPlugin_Hypothesis::SetEnforcedGroup");
701   TIDSortedElemSet theElemSet;
702     if ( theIDs->length() == 0 ){MESSAGE("The source group is empty");}
703     for ( CORBA::ULong i = 0; i < theIDs->length(); i++) {
704       SMESH::smIdType ind = theIDs[i];
705       if (elementType == SMESH::NODE)
706       {
707         const SMDS_MeshNode * node = theMeshDS->FindNode(ind);
708         if (node)
709           theElemSet.insert( node );
710       }
711       else
712       {
713         const SMDS_MeshElement * elem = theMeshDS->FindElement(ind);
714         if (elem)
715           theElemSet.insert( elem );
716       }
717     }
718
719 //   SMDS_ElemIteratorPtr it = theGroup->GetGroupDS()->GetElements();
720 //   while ( it->more() ) 
721 //     theElemSet.insert( it->next() );
722
723   MESSAGE("Add "<<theElemSet.size()<<" types["<<elementType<<"] from source group ");
724   bool added = SetEnforcedElements( theElemSet, elementType, groupName);
725   if (added) {
726     TGHS3DEnforcedMesh* newEnfMesh = new TGHS3DEnforcedMesh();
727     newEnfMesh->name = name;
728     newEnfMesh->entry = entry;
729     newEnfMesh->elementType = elementType;
730     newEnfMesh->groupName = groupName;
731     
732     TGHS3DEnforcedMeshList::iterator it = _enfMeshList.find(newEnfMesh);
733     if (it == _enfMeshList.end()) {
734       _entryEnfMeshMap[entry].insert(newEnfMesh);
735       _enfMeshList.insert(newEnfMesh);
736     }
737   }
738   return added;
739 }
740
741 //=======================================================================
742 //function : SetEnforcedElements
743 //=======================================================================
744 bool GHS3DPlugin_Hypothesis::SetEnforcedElements(TIDSortedElemSet theElemSet, SMESH::ElementType elementType, std::string groupName)
745 {
746   MESSAGE("GHS3DPlugin_Hypothesis::SetEnforcedElements");
747   TIDSortedElemSet::const_iterator it = theElemSet.begin();
748   const SMDS_MeshElement* elem;
749   const SMDS_MeshNode* node;
750   bool added = true;
751   pair<TIDSortedNodeGroupMap::iterator,bool> nodeRet;
752   pair<TIDSortedElemGroupMap::iterator,bool> elemRet;
753
754   for (;it != theElemSet.end();++it)
755   {
756     elem = (*it);
757     switch (elementType) {
758       case SMESH::NODE:
759         node = dynamic_cast<const SMDS_MeshNode*>(elem);
760         if (node) {
761           nodeRet = _enfNodes.insert(make_pair(node,groupName));
762           added = added && nodeRet.second;
763           string msg = added ? "yes":"no";
764           MESSAGE( "Node (" <<node->X()<<","<<node->Y()<<","<<node->Z()<< ") with ID " << node->GetID() <<" added ? " << msg);
765         }
766         else {
767           SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
768           for (;nodeIt->more();) {
769             node = dynamic_cast<const SMDS_MeshNode*>(nodeIt->next());
770             nodeRet = _enfNodes.insert(make_pair(node,groupName));
771             added = added && nodeRet.second;
772           }
773         }
774         break;
775       case SMESH::EDGE:
776         if (elem->GetType() == SMDSAbs_Edge) {
777           elemRet = _enfEdges.insert(make_pair(elem,groupName));
778           added = added && elemRet.second;
779         }
780         else if (elem->GetType() > SMDSAbs_Edge) {
781           // SMDS_ElemIteratorPtr it = elem->edgesIterator();
782           // for (;it->more();) {
783           //   const SMDS_MeshElement* anEdge = it->next();
784           //   elemRet = _enfEdges.insert(make_pair(anEdge,groupName));
785           //   added = added && elemRet.second;
786           // }
787         }
788         break;
789       case SMESH::FACE:
790         if (elem->GetType() == SMDSAbs_Face)
791         {
792           if (elem->NbCornerNodes() == 3) {
793             elemRet = _enfTriangles.insert(make_pair(elem,groupName));
794             added = added && elemRet.second;
795           }
796         }
797         else if (elem->GetType() > SMDSAbs_Face) { // Group of faces
798           // SMDS_ElemIteratorPtr it = elem->facesIterator();
799           // for (;it->more();) {
800           //   const SMDS_MeshElement* aFace = it->next();
801           //   if (aFace->NbCornerNodes() == 3) {
802           //     elemRet = _enfTriangles.insert(make_pair(aFace,groupName));
803           //     added = added && elemRet.second;
804           //   }
805           // }
806         }
807         break;
808       default:
809         break;
810     };
811   }
812   if (added)
813     NotifySubMeshesHypothesisModification();
814   return added;
815 }
816
817
818 //=======================================================================
819 //function : GetEnforcedVertex
820 //=======================================================================
821
822 GHS3DPlugin_Hypothesis::TGHS3DEnforcedVertex* GHS3DPlugin_Hypothesis::GetEnforcedVertex(double x, double y, double z)
823 {
824   std::vector<double> coord(3);
825   coord[0] = x;
826   coord[1] = y;
827   coord[2] = z;
828   if (_coordsEnfVertexMap.count(coord)>0)
829     return _coordsEnfVertexMap[coord];
830   std::ostringstream msg ;
831   msg << "No enforced vertex at " << x << ", " << y << ", " << z;
832   throw std::invalid_argument(msg.str());
833 }
834
835 GHS3DPlugin_Hypothesis::TGHS3DEnforcedVertex* GHS3DPlugin_Hypothesis::GetEnforcedVertex(const std::string theEntry)
836 {
837   if (_geomEntryEnfVertexMap.count(theEntry)>0)
838     return _geomEntryEnfVertexMap[theEntry];
839   
840   std::ostringstream msg ;
841   msg << "No enforced vertex with entry " << theEntry;
842   throw std::invalid_argument(msg.str());
843 }
844
845 //=======================================================================
846 //function : RemoveEnforcedVertex
847 //=======================================================================
848
849 bool GHS3DPlugin_Hypothesis::RemoveEnforcedVertex(double x, double y, double z, const std::string theEntry)
850 {
851   bool toNotify = false;
852   std::ostringstream msg;
853   TGHS3DEnforcedVertex *oldEnfVertex;
854   std::vector<double> coords(3);
855   coords[0] = x;
856   coords[1] = y;
857   coords[2] = z;
858   
859   // check that enf vertex with given enf vertex entry exists
860   TGeomEntryGHS3DEnforcedVertexMap::iterator it_enfVertexEntry = _geomEntryEnfVertexMap.find(theEntry);
861   if (it_enfVertexEntry != _geomEntryEnfVertexMap.end()) {
862     // Success
863     MESSAGE("Found enforced vertex with geom entry " << theEntry);
864     oldEnfVertex = it_enfVertexEntry->second;
865     _geomEntryEnfVertexMap.erase(it_enfVertexEntry);
866   } else {
867     // Fail
868     MESSAGE("Enforced vertex with geom entry " << theEntry << " not found");
869     // check that enf vertex with given coords exists
870     TCoordsGHS3DEnforcedVertexMap::iterator it_coords_enf = _coordsEnfVertexMap.find(coords);
871     if (it_coords_enf != _coordsEnfVertexMap.end()) {
872       // Success
873       MESSAGE("Found enforced vertex with coords " << x << ", " << y << ", " << z);
874       oldEnfVertex = it_coords_enf->second;
875       _coordsEnfVertexMap.erase(it_coords_enf);
876       _enfVertexCoordsSizeList.erase(_enfVertexCoordsSizeList.find(coords));
877     } else {
878       // Fail
879       MESSAGE("Enforced vertex with coords " << x << ", " << y << ", " << z << " not found");
880       throw std::invalid_argument(msg.str());
881     }
882   }
883
884   MESSAGE("Remove enf vertex from _enfVertexList");
885
886   // update _enfVertexList
887   TGHS3DEnforcedVertexList::iterator it = _enfVertexList.find(oldEnfVertex);
888   if (it != _enfVertexList.end()) {
889     if ((*it)->groupName != "")
890       _groupsToRemove.insert((*it)->groupName);
891     _enfVertexList.erase(it);
892     toNotify = true;
893     MESSAGE("Done");
894   }
895
896   if (toNotify)
897     NotifySubMeshesHypothesisModification();
898
899   return toNotify;
900 }
901
902 //=======================================================================
903 //function : ClearEnforcedVertices
904 //=======================================================================
905 void GHS3DPlugin_Hypothesis::ClearEnforcedVertices()
906 {
907   TGHS3DEnforcedVertexList::const_iterator it = _enfVertexList.begin();
908   for(;it != _enfVertexList.end();++it) {
909     if ((*it)->groupName != "")
910       _groupsToRemove.insert((*it)->groupName);
911   }
912   _enfVertexList.clear();
913   _coordsEnfVertexMap.clear();
914   _geomEntryEnfVertexMap.clear();
915   _enfVertexCoordsSizeList.clear();
916   _enfVertexEntrySizeList.clear();
917   NotifySubMeshesHypothesisModification();
918 }
919
920 //=======================================================================
921 //function : ClearEnforcedMeshes
922 //=======================================================================
923 void GHS3DPlugin_Hypothesis::ClearEnforcedMeshes()
924 {
925   TGHS3DEnforcedMeshList::const_iterator it = _enfMeshList.begin();
926   for(;it != _enfMeshList.end();++it) {
927     if ((*it)->groupName != "")
928       _groupsToRemove.insert((*it)->groupName);
929   }
930   _enfNodes.clear();
931   _enfEdges.clear();
932   _enfTriangles.clear();
933   _nodeIDToSizeMap.clear();
934   _enfMeshList.clear();
935   _entryEnfMeshMap.clear();
936   NotifySubMeshesHypothesisModification();
937 }
938
939 //================================================================================
940 /*!
941  * \brief At mesh loading, restore enforced elements by just loaded enforced meshes
942  */
943 //================================================================================
944
945 void GHS3DPlugin_Hypothesis::RestoreEnfElemsByMeshes()
946 {
947   TGHS3DEnforcedMeshList::const_iterator it = _enfMeshList.begin();
948   for(;it != _enfMeshList.end();++it) {
949     TGHS3DEnforcedMesh* enfMesh = *it;
950     if ( SMESH_Mesh* mesh = GetMeshByPersistentID( enfMesh->persistID ))
951       SetEnforcedMesh( *mesh,
952                        enfMesh->elementType,
953                        enfMesh->name,
954                        enfMesh->entry,
955                        enfMesh->groupName );
956     enfMesh->persistID = -1; // not to restore again
957   }
958 }
959
960 //=======================================================================
961 //function : SetGroupsToRemove
962 //=======================================================================
963
964 void GHS3DPlugin_Hypothesis::ClearGroupsToRemove()
965 {
966   _groupsToRemove.clear();
967 }
968
969
970 //=======================================================================
971 //function : DefaultMeshHoles
972 //=======================================================================
973
974 bool GHS3DPlugin_Hypothesis::DefaultMeshHoles()
975 {
976   return false; // PAL19680
977 }
978
979 //=======================================================================
980 //function : DefaultToMakeGroupsOfDomains
981 //=======================================================================
982
983 bool GHS3DPlugin_Hypothesis::DefaultToMakeGroupsOfDomains()
984 {
985   return false; // issue 0022172
986 }
987
988 //=======================================================================
989 //function : DefaultMaximumMemory
990 //=======================================================================
991
992 #if defined(WIN32)
993 #include <windows.h>
994 #elif !defined(__APPLE__)
995 #include <sys/sysinfo.h>
996 #endif
997
998 float GHS3DPlugin_Hypothesis::DefaultMaximumMemory()
999 {
1000 #if defined(WIN32)
1001   // See http://msdn.microsoft.com/en-us/library/aa366589.aspx
1002   MEMORYSTATUSEX statex;
1003   statex.dwLength = sizeof (statex);
1004   long err = GlobalMemoryStatusEx (&statex);
1005   if (err != 0) {
1006     double totMB = double( statex.ullAvailPhys ) / 1024. / 1024.;
1007     return float( 0.7 * totMB );
1008   }
1009 #elif !defined(__APPLE__)
1010   struct sysinfo si;
1011   long err = sysinfo( &si );
1012   if ( err == 0 ) {
1013     double ramMB = double( si.totalram * si.mem_unit / 1024 / 1024 );
1014     return float( 0.7 * ramMB );
1015   }
1016 #endif
1017   return 1024;
1018 }
1019
1020 //=======================================================================
1021 //function : DefaultInitialMemory
1022 //=======================================================================
1023
1024 float GHS3DPlugin_Hypothesis::DefaultInitialMemory()
1025 {
1026   return DefaultMaximumMemory();
1027 }
1028
1029 //=======================================================================
1030 //function : DefaultOptimizationLevel
1031 //=======================================================================
1032
1033 short GHS3DPlugin_Hypothesis::DefaultOptimizationLevel()
1034 {
1035   return Medium;
1036 }
1037
1038 //=======================================================================
1039 //function : DefaultWorkingDirectory
1040 //=======================================================================
1041
1042 std::string GHS3DPlugin_Hypothesis::DefaultWorkingDirectory()
1043 {
1044   TCollection_AsciiString aTmpDir;
1045
1046   char *Tmp_dir = getenv("SALOME_TMP_DIR");
1047   if(Tmp_dir != NULL) {
1048     aTmpDir = Tmp_dir;
1049   }
1050   else {
1051 #ifdef WIN32
1052     aTmpDir = TCollection_AsciiString("C:\\");
1053 #else
1054     aTmpDir = TCollection_AsciiString("/tmp/");
1055 #endif
1056   }
1057   return aTmpDir.ToCString();
1058 }
1059
1060 //=======================================================================
1061 //function : DefaultKeepFiles
1062 //=======================================================================
1063
1064 bool   GHS3DPlugin_Hypothesis::DefaultKeepFiles()
1065 {
1066   return false;
1067 }
1068
1069 //=======================================================================
1070 //function : DefaultRemoveLogOnSuccess
1071 //=======================================================================
1072
1073 bool   GHS3DPlugin_Hypothesis::DefaultRemoveLogOnSuccess()
1074 {
1075   return false;
1076 }
1077
1078
1079 //=======================================================================
1080 //function : DefaultVerboseLevel
1081 //=======================================================================
1082
1083 short  GHS3DPlugin_Hypothesis::DefaultVerboseLevel()
1084 {
1085   return 10;
1086 }
1087
1088 //=======================================================================
1089 //function : DefaultToCreateNewNodes
1090 //=======================================================================
1091
1092 bool GHS3DPlugin_Hypothesis::DefaultToCreateNewNodes()
1093 {
1094   return true;
1095 }
1096
1097 //=======================================================================
1098 //function : DefaultToUseBoundaryRecoveryVersion
1099 //=======================================================================
1100
1101 bool GHS3DPlugin_Hypothesis::DefaultToUseBoundaryRecoveryVersion()
1102 {
1103   return false;
1104 }
1105
1106 //=======================================================================
1107 //function : DefaultToUseFEMCorrection
1108 //=======================================================================
1109
1110 bool GHS3DPlugin_Hypothesis::DefaultToUseFEMCorrection()
1111 {
1112   return false;
1113 }
1114
1115 //=======================================================================
1116 //function : DefaultToRemoveCentralPoint
1117 //=======================================================================
1118
1119 bool GHS3DPlugin_Hypothesis::DefaultToRemoveCentralPoint()
1120 {
1121   return false;
1122 }
1123
1124 //=======================================================================
1125 //function : DefaultStandardOutputLog
1126 //=======================================================================
1127
1128 bool GHS3DPlugin_Hypothesis::DefaultStandardOutputLog()
1129 {
1130   return false;
1131 }
1132
1133 // //=======================================================================
1134 // //function : DefaultID2SizeMap
1135 // //=======================================================================
1136 // 
1137 // GHS3DPlugin_Hypothesis::TID2SizeMap GHS3DPlugin_Hypothesis::DefaultID2SizeMap()
1138 // {
1139 //   return GHS3DPlugin_Hypothesis::TID2SizeMap();
1140 // }
1141
1142
1143 //=======================================================================
1144 //function : SaveTo
1145 //=======================================================================
1146
1147 std::ostream & GHS3DPlugin_Hypothesis::SaveTo(std::ostream & save)
1148 {
1149   save << (int) myToMeshHoles                 << " ";
1150   save << myMaximumMemory                     << " ";
1151   save << myInitialMemory                     << " ";
1152   save << myOptimizationLevel                 << " ";
1153   save << myWorkingDirectory                  << " ";
1154   save << (int)myKeepFiles                    << " ";
1155   save << myVerboseLevel                      << " ";
1156   save << (int)myToCreateNewNodes             << " ";
1157   save << (int)myToUseBoundaryRecoveryVersion << " ";
1158   save << (int)myToUseFemCorrection           << " ";
1159   save << (int)myToRemoveCentralPoint         << " ";
1160   save << myGradation                         << " ";
1161   save << myToMakeGroupsOfDomains             << " ";
1162   // if (!myTextOption.empty()) {
1163   //   save << "__OPTIONS_BEGIN__ ";
1164   //   save << myTextOption                      << " ";
1165   //   save << "__OPTIONS_END__ ";
1166   // }
1167   
1168
1169   TGHS3DEnforcedVertexList::iterator it  = _enfVertexList.begin();
1170   if (it != _enfVertexList.end()) {
1171     save << " " << "__ENFORCED_VERTICES_BEGIN__ ";
1172     for ( ; it != _enfVertexList.end(); ++it ) {
1173       TGHS3DEnforcedVertex *enfVertex = (*it);
1174       save << " " << "__BEGIN_VERTEX__";
1175       if (!enfVertex->name.empty()) {
1176         save << " " << "__BEGIN_NAME__";
1177         save << " " << enfVertex->name;
1178         save << " " << "__END_NAME__";
1179       }
1180       if (!enfVertex->geomEntry.empty()) {
1181         save << " " << "__BEGIN_ENTRY__";
1182         save << " " << enfVertex->geomEntry;
1183         save << " " << enfVertex->isCompound;
1184         save << " " << "__END_ENTRY__";
1185       }
1186       if (!enfVertex->groupName.empty()) {
1187         save << " " << "__BEGIN_GROUP__";
1188         save << " " << enfVertex->groupName;
1189         save << " " << "__END_GROUP__";
1190       }
1191       if (enfVertex->coords.size()) {
1192         save << " " << "__BEGIN_COORDS__";
1193         for ( size_t i = 0; i < enfVertex->coords.size(); i++ )
1194           save << " " << enfVertex->coords[i];
1195         save << " " << "__END_COORDS__";
1196       }
1197       save << " " << "__BEGIN_SIZE__";
1198       save << " " << enfVertex->size;
1199       save << " " << "__END_SIZE__";
1200       save << " " << "__END_VERTEX__";
1201     }
1202     save << " " << "__ENFORCED_VERTICES_END__ ";
1203   }
1204
1205   TGHS3DEnforcedMeshList::iterator it_mesh  = _enfMeshList.begin();
1206   if (it_mesh != _enfMeshList.end()) {
1207     save << " " << "__ENFORCED_MESHES_BEGIN__ ";
1208     for ( ; it_mesh != _enfMeshList.end(); ++it_mesh ) {
1209       TGHS3DEnforcedMesh *enfMesh = (*it_mesh);
1210       save << " " << "__BEGIN_ENF_MESH__";
1211
1212       save << " " << "__BEGIN_NAME__";
1213       save << " " << enfMesh->name;
1214       save << " " << "__END_NAME__";
1215
1216       save << " " << "__BEGIN_ENTRY__";
1217       save << " " << enfMesh->entry;
1218       save << " " << "__END_ENTRY__";
1219
1220       save << " " << "__BEGIN_ELEM_TYPE__";
1221       save << " " << (int)enfMesh->elementType;
1222       save << " " << "__END_ELEM_TYPE__";
1223
1224       if (!enfMesh->groupName.empty()) {
1225         save << " " << "__BEGIN_GROUP__";
1226         save << " " << enfMesh->groupName;
1227         save << " " << "__END_GROUP__";
1228       }
1229       save << " " << "__PERSIST_ID__";
1230       save << " " << enfMesh->persistID;
1231       save << " " << "__END_ENF_MESH__";
1232       std::cout << "Saving of enforced mesh " << enfMesh->name.c_str() << " done" << std::endl;
1233     }
1234     save << " "  << "__ENFORCED_MESHES_END__ ";
1235   }
1236
1237   // New options in 2.9.6 (issue #17784)
1238
1239   save << " " << myUseVolumeProximity;
1240   save << " " << myNbVolumeProximityLayers;
1241   save << " " << myMinSize;
1242   save << " " << myMaxSize;
1243   save << " " << myMinSizeDefault;
1244   save << " " << myMaxSizeDefault;
1245
1246   save << " " << _option2value.size();
1247   TOptionValues::iterator o2v = _option2value.begin();
1248   for ( ; o2v != _option2value.end(); ++o2v )
1249     save << " -" << o2v->first << " -" << o2v->second;
1250   
1251   save << " " << _customOption2value.size();
1252   for ( o2v = _customOption2value.begin(); o2v != _customOption2value.end(); ++o2v )
1253     save << " -" << o2v->first << " -" << o2v->second;
1254
1255   return save;
1256 }
1257
1258 //=======================================================================
1259 //function : LoadFrom
1260 //=======================================================================
1261
1262 std::istream & GHS3DPlugin_Hypothesis::LoadFrom(std::istream & load)
1263 {
1264   bool isOK = true;
1265   int i;
1266   double d;
1267
1268   isOK = static_cast<bool>(load >> i);
1269   if (isOK)
1270     myToMeshHoles = i;
1271   else
1272     load.clear(ios::badbit | load.rdstate());
1273
1274   isOK = static_cast<bool>(load >> d);
1275   if (isOK)
1276     myMaximumMemory = float( d );
1277   else
1278     load.clear(ios::badbit | load.rdstate());
1279
1280   isOK = static_cast<bool>(load >> d);
1281   if (isOK)
1282     myInitialMemory = float( d );
1283   else
1284     load.clear(ios::badbit | load.rdstate());
1285
1286   isOK = static_cast<bool>(load >> i);
1287   if (isOK)
1288     myOptimizationLevel = (short int) i;
1289   else
1290     load.clear(ios::badbit | load.rdstate());
1291
1292   isOK = static_cast<bool>(load >> myWorkingDirectory);
1293   if (isOK) {
1294     if ( myWorkingDirectory == "0") { // myWorkingDirectory was empty
1295       myKeepFiles = false;
1296       myWorkingDirectory.clear();
1297     }
1298     else if ( myWorkingDirectory == "1" ) {
1299       myKeepFiles = true;
1300       myWorkingDirectory.clear();
1301     }
1302   }
1303   else
1304     load.clear(ios::badbit | load.rdstate());
1305
1306   if ( !myWorkingDirectory.empty() ) {
1307     isOK = static_cast<bool>(load >> i);
1308     if (isOK)
1309       myKeepFiles = i;
1310     else
1311       load.clear(ios::badbit | load.rdstate());
1312   }
1313
1314   isOK = static_cast<bool>(load >> i);
1315   if (isOK)
1316     myVerboseLevel = (short) i;
1317   else
1318     load.clear(ios::badbit | load.rdstate());
1319
1320   isOK = static_cast<bool>(load >> i);
1321   if (isOK)
1322     myToCreateNewNodes = (bool) i;
1323   else
1324     load.clear(ios::badbit | load.rdstate());
1325
1326   isOK = static_cast<bool>(load >> i);
1327   if (isOK)
1328     myToUseBoundaryRecoveryVersion = (bool) i;
1329   else
1330     load.clear(ios::badbit | load.rdstate());
1331
1332   isOK = static_cast<bool>(load >> i);
1333   if (isOK)
1334     myToUseFemCorrection = (bool) i;
1335   else
1336     load.clear(ios::badbit | load.rdstate());
1337
1338   isOK = static_cast<bool>(load >> i);
1339   if (isOK)
1340     myToRemoveCentralPoint = (bool) i;
1341   else
1342     load.clear(ios::badbit | load.rdstate());
1343
1344   isOK = static_cast<bool>(load >> d);
1345   if (isOK)
1346     myGradation = d;
1347   else
1348     load.clear(ios::badbit | load.rdstate());
1349
1350   std::string separator;
1351   bool hasOptions = false;
1352   bool hasEnforcedVertices = false;
1353   bool hasEnforcedMeshes = false;
1354   isOK = static_cast<bool>(load >> separator);
1355
1356   if ( isOK && ( separator == "0" || separator == "1" ))
1357   {
1358     myToMakeGroupsOfDomains = ( separator == "1" );
1359     isOK = static_cast<bool>(load >> separator);
1360   }
1361
1362   if (isOK) {
1363     if (separator == "__OPTIONS_BEGIN__")
1364       hasOptions = true;
1365     else if (separator == "__ENFORCED_VERTICES_BEGIN__")
1366       hasEnforcedVertices = true;
1367     else if (separator == "__ENFORCED_MESHES_BEGIN__")
1368       hasEnforcedMeshes = true;
1369   }
1370
1371   if (hasOptions) {
1372     std::string txt;
1373     while (isOK) {
1374       isOK = static_cast<bool>(load >> txt);
1375       if (isOK) {
1376         if (txt == "__OPTIONS_END__") {
1377           // if (!myTextOption.empty()) {
1378           //   // Remove last space
1379           //   myTextOption.erase(myTextOption.end()-1);
1380           // }
1381           isOK = false;
1382           break;
1383         }
1384         // myTextOption += txt;
1385         // myTextOption += " ";
1386       }
1387     }
1388   }
1389
1390   if (hasOptions) {
1391     isOK = static_cast<bool>(load >> separator);
1392     if (isOK && separator == "__ENFORCED_VERTICES_BEGIN__")
1393       hasEnforcedVertices = true;
1394     if (isOK && separator == "__ENFORCED_MESHES_BEGIN__")
1395       hasEnforcedMeshes = true;
1396   }
1397
1398   if (hasEnforcedVertices) {
1399     std::string txt, name, entry, groupName;
1400     double size, coords[3];
1401     bool isCompound;
1402     bool hasCoords = false;
1403     isOK = static_cast<bool>(load >> txt);  // __BEGIN_VERTEX__
1404     while (isOK) {
1405       if (txt == "__ENFORCED_VERTICES_END__") {
1406         //isOK = false;
1407         break;
1408       }
1409       
1410       TGHS3DEnforcedVertex *enfVertex = new TGHS3DEnforcedVertex();
1411       while (isOK) {
1412         isOK = static_cast<bool>(load >> txt);
1413         if (txt == "__END_VERTEX__") {
1414           enfVertex->name = name;
1415           enfVertex->geomEntry = entry;
1416           enfVertex->isCompound = isCompound;
1417           enfVertex->groupName = groupName;
1418           enfVertex->coords.clear();
1419           if (hasCoords)
1420             enfVertex->coords.assign(coords,coords+3);
1421
1422           _enfVertexList.insert(enfVertex);
1423
1424           if (enfVertex->coords.size())
1425             _coordsEnfVertexMap[enfVertex->coords] = enfVertex;
1426           if (!enfVertex->geomEntry.empty())
1427             _geomEntryEnfVertexMap[enfVertex->geomEntry] = enfVertex;
1428
1429           name.clear();
1430           entry.clear();
1431           groupName.clear();
1432           hasCoords = false;
1433           isOK = false;
1434         }
1435
1436         if (txt == "__BEGIN_NAME__") {  // __BEGIN_NAME__
1437           while (isOK && (txt != "__END_NAME__")) {
1438             isOK = static_cast<bool>(load >> txt);
1439             if (txt != "__END_NAME__") {
1440               if (!name.empty())
1441                 name += " ";
1442               name += txt;
1443             }
1444           }
1445           MESSAGE("name: " <<name);
1446         }
1447
1448         if (txt == "__BEGIN_ENTRY__") {  // __BEGIN_ENTRY__
1449           isOK = static_cast<bool>(load >> entry);
1450           isOK = static_cast<bool>(load >> isCompound);
1451           isOK = static_cast<bool>(load >> txt); // __END_ENTRY__
1452           if (txt != "__END_ENTRY__")
1453             throw std::exception();
1454           MESSAGE("entry: " << entry);
1455         }
1456
1457         if (txt == "__BEGIN_GROUP__") {  // __BEGIN_GROUP__
1458           while (isOK && (txt != "__END_GROUP__")) {
1459             isOK = static_cast<bool>(load >> txt);
1460             if (txt != "__END_GROUP__") {
1461               if (!groupName.empty())
1462                 groupName += " ";
1463               groupName += txt;
1464             }
1465           }
1466           MESSAGE("groupName: " << groupName);
1467         }
1468
1469         if (txt == "__BEGIN_COORDS__") {  // __BEGIN_COORDS__
1470           hasCoords = true;
1471           isOK = static_cast<bool>(load >> coords[0] >> coords[1] >> coords[2]);
1472           isOK = static_cast<bool>(load >> txt); // __END_COORDS__
1473           if (txt != "__END_COORDS__")
1474             throw std::exception();
1475           MESSAGE("coords: " << coords[0] <<","<< coords[1] <<","<< coords[2]);
1476         }
1477
1478         if (txt == "__BEGIN_SIZE__") {  // __BEGIN_ENTRY__
1479           isOK = static_cast<bool>(load >> size);
1480           isOK = static_cast<bool>(load >> txt); // __END_ENTRY__
1481           if (txt != "__END_SIZE__") {
1482             throw std::exception();
1483           }
1484           MESSAGE("size: " << size);
1485         }
1486       }
1487       isOK = static_cast<bool>(load >> txt);  // __BEGIN_VERTEX__
1488     }
1489   }
1490
1491   if (hasEnforcedVertices) {
1492     isOK = static_cast<bool>(load >> separator);
1493     if (isOK && separator == "__ENFORCED_MESHES_BEGIN__")
1494       hasEnforcedMeshes = true;
1495   }
1496
1497   if (hasEnforcedMeshes) {
1498     std::string txt, name, entry, groupName;
1499     int elementType = -1, persistID = -1;
1500     isOK = static_cast<bool>(load >> txt);  // __BEGIN_ENF_MESH__
1501     while (isOK) {
1502       //                if (isOK) {
1503       if (txt == "__ENFORCED_MESHES_END__")
1504         isOK = false;
1505
1506       TGHS3DEnforcedMesh *enfMesh = new TGHS3DEnforcedMesh();
1507       while (isOK) {
1508         isOK = static_cast<bool>(load >> txt);
1509         if (txt == "__END_ENF_MESH__") {
1510           enfMesh->name = name;
1511           enfMesh->entry = entry;
1512           enfMesh->elementType = (SMESH::ElementType)elementType;
1513           enfMesh->groupName = groupName;
1514           enfMesh->persistID = persistID;
1515
1516           _enfMeshList.insert(enfMesh);
1517           //std::cout << "Restoring of enforced mesh " <<name  << " done" << std::endl;
1518
1519           name.clear();
1520           entry.clear();
1521           elementType = -1;
1522           groupName.clear();
1523           persistID = -1;
1524           isOK = false;
1525         }
1526
1527         if (txt == "__BEGIN_NAME__") {  // __BEGIN_NAME__
1528           while (isOK && (txt != "__END_NAME__")) {
1529             isOK = static_cast<bool>(load >> txt);
1530             if (txt != "__END_NAME__") {
1531               if (!name.empty())
1532                 name += " ";
1533               name += txt;
1534             }
1535           }
1536           MESSAGE("name: " <<name);
1537         }
1538
1539         if (txt == "__BEGIN_ENTRY__") {  // __BEGIN_ENTRY__
1540           isOK = static_cast<bool>(load >> entry);
1541           isOK = static_cast<bool>(load >> txt); // __END_ENTRY__
1542           if (txt != "__END_ENTRY__")
1543             throw std::exception();
1544           MESSAGE("entry: " << entry);
1545         }
1546
1547         if (txt == "__BEGIN_ELEM_TYPE__") {  // __BEGIN_ELEM_TYPE__
1548           isOK = static_cast<bool>(load >> elementType);
1549           isOK = static_cast<bool>(load >> txt); // __END_ELEM_TYPE__
1550           if (txt != "__END_ELEM_TYPE__")
1551             throw std::exception();
1552           MESSAGE("elementType: " << elementType);
1553         }
1554
1555         if (txt == "__BEGIN_GROUP__") {  // __BEGIN_GROUP__
1556           while (isOK && (txt != "__END_GROUP__")) {
1557             isOK = static_cast<bool>(load >> txt);
1558             if (txt != "__END_GROUP__") {
1559               if (!groupName.empty())
1560                 groupName += " ";
1561               groupName += txt;
1562             }
1563           } // while
1564           MESSAGE("groupName: " << groupName);
1565         } // if
1566
1567         if (txt == "__PERSIST_ID__") {
1568           isOK = static_cast<bool>(load >> persistID);
1569           MESSAGE("persistID: " << persistID);
1570         }
1571         //std::cout << "isOK: " << isOK << std::endl;
1572       } // while
1573       //                } // if
1574       isOK = static_cast<bool>(load >> txt);  // __BEGIN_ENF_MESH__
1575     } // while
1576   } // if
1577
1578   // New options in 2.9.6 (issue #17784)
1579
1580   if ( ! hasOptions && ! hasEnforcedVertices && ! hasEnforcedMeshes )
1581     myUseVolumeProximity = ( separator == "1" );
1582   else if ( static_cast<bool>( load >> i ))
1583     myUseVolumeProximity = (bool) i;
1584
1585   if ( static_cast<bool>( load >> myNbVolumeProximityLayers ))
1586   {
1587     load >> myMinSize;
1588     load >> myMaxSize;
1589     load >> myMinSizeDefault;
1590     load >> myMaxSizeDefault;
1591
1592     std::string option, value;
1593     if ( static_cast<bool>( load >> i ) && i >= 0 )
1594     {
1595       for ( int nbRead = 0; nbRead < i; ++nbRead )
1596       {
1597         load >> option >> value;
1598         _option2value[ std::string( option, 1 )] = std::string( value, 1 );
1599       }
1600     }
1601     if ( static_cast<bool>( load >> i ) && i >= 0 )
1602     {
1603       for ( int nbRead = 0; nbRead < i; ++nbRead )
1604       {
1605         load >> option >> value;
1606         _customOption2value[ std::string( option, 1 )] = std::string( value, 1 );
1607       }
1608     }
1609   }
1610
1611   return load;
1612 }
1613
1614 //=======================================================================
1615 //function : SetParametersByMesh
1616 //=======================================================================
1617
1618 bool GHS3DPlugin_Hypothesis::SetParametersByMesh(const SMESH_Mesh* ,const TopoDS_Shape&)
1619 {
1620   return false;
1621 }
1622
1623
1624 //================================================================================
1625 /*!
1626  * \brief Sets myToMakeGroupsOfDomains depending on whether theMesh is on shape or not
1627  */
1628 //================================================================================
1629
1630 bool GHS3DPlugin_Hypothesis::SetParametersByDefaults(const TDefaults&  dflts,
1631                                                      const SMESH_Mesh* /*theMesh*/)
1632 {
1633   myToMakeGroupsOfDomains = ( !dflts._shape || dflts._shape->IsNull() );
1634
1635   double diagonal = dflts._elemLength * _gen->GetBoundaryBoxSegmentation();
1636   myMinSizeDefault = 1e-3 * diagonal;
1637   myMaxSizeDefault = diagonal / 5.;
1638
1639   return true;
1640 }
1641
1642 //================================================================================
1643 /*!
1644  * \brief Return command to run MG-Tetra mesher excluding file prefix (-f)
1645  */
1646 //================================================================================
1647
1648 std::string GHS3DPlugin_Hypothesis::CommandToRun(const GHS3DPlugin_Hypothesis* hyp,
1649                                                  const bool                    hasShapeToMesh,
1650                                                  const bool                    forExecutable)
1651 {
1652   std::string cmd = GetExeName();
1653   // check if any option is overridden by hyp->myTextOption
1654   bool max_memory     = hyp ? !hyp->HasOptionDefined("max_memory")               : true;
1655   bool auto_memory    = hyp ? !hyp->HasOptionDefined("automatic_memory")         : true;
1656   bool comp           = hyp ? !hyp->HasOptionDefined("components")               : true;
1657   bool optim_level    = hyp ? !hyp->HasOptionDefined("optimisation_level")       : true;
1658   bool no_int_points  = hyp ? !hyp->HasOptionDefined("no_internal_points")       : true;
1659   bool C              = hyp ? !hyp->HasOptionDefined("-C")                       : true;
1660   bool verbose        = hyp ? !hyp->HasOptionDefined("verbose")                  : true;
1661   bool gra            = hyp ? !hyp->HasOptionDefined("-Dcpropa")                 : true;
1662   bool rem            = hyp ? !hyp->HasOptionDefined("no_initial_central_point") : true;
1663   //bool fem            = hyp ? !hyp->HasOptionDefined("-FEM")                     : true;
1664
1665   // if use boundary recovery version, few options are allowed
1666   bool useBndRecovery = !C;
1667   if ( !useBndRecovery && hyp )
1668     useBndRecovery = hyp->myToUseBoundaryRecoveryVersion;
1669
1670   // MG-Tetra needs to know amount of memory it may use (MB).
1671   // Default memory is defined at MG-Tetra installation but it may be not enough,
1672   // so allow to use about all available memory
1673   if ( max_memory ) {
1674     float aMaximumMemory = hyp ? hyp->myMaximumMemory : -1;
1675     cmd += " --max_memory ";
1676     if ( aMaximumMemory < 0 ) cmd += SMESH_Comment( int( DefaultMaximumMemory() ));
1677     else                      cmd += SMESH_Comment( int( aMaximumMemory ));
1678   }
1679   if ( auto_memory && !useBndRecovery ) {
1680     float aInitialMemory = hyp ? hyp->myInitialMemory : -1;
1681     cmd += " --automatic_memory ";
1682     if ( aInitialMemory > 0 ) cmd += SMESH_Comment( int( aInitialMemory ));
1683     else                      cmd += "100";
1684   }
1685   // component to mesh
1686   if ( comp && !useBndRecovery ) {
1687     // We always run MG-Tetra with "to mesh holes'==TRUE (see PAL19680)
1688     if ( hasShapeToMesh )
1689       cmd += " --components all";
1690     else {
1691       bool aToMeshHoles = hyp ? hyp->myToMeshHoles : DefaultMeshHoles();
1692       if ( aToMeshHoles ) cmd += " --components all";
1693       else                cmd += " --components outside_components";
1694     }
1695   }
1696   const bool toCreateNewNodes = ( no_int_points && ( !hyp || hyp->myToCreateNewNodes ));
1697
1698   // optimization level
1699   if ( !toCreateNewNodes ) {
1700     cmd += " --optimisation_level none"; // issue 22608
1701   }
1702   else if ( optim_level && hyp && !useBndRecovery ) {
1703     if ( hyp->myOptimizationLevel >= 0 && hyp->myOptimizationLevel < 5 ) {
1704       const char* level[] = { "none" , "light" , "standard" , "standard+" , "strong" };
1705       cmd += " --optimisation_level ";
1706       cmd += level[ hyp->myOptimizationLevel ];
1707     }
1708   }
1709
1710   // to create internal nodes
1711   if ( no_int_points && !toCreateNewNodes ) {
1712     if ( forExecutable )
1713       cmd += " --no_internal_points";
1714     else
1715       cmd += " --internalpoints no";
1716   }
1717
1718   // verbose mode
1719   if ( verbose && hyp ) {
1720     cmd += " --verbose " + SMESH_Comment( hyp->myVerboseLevel );
1721   }
1722
1723   // boundary recovery version
1724   // if ( useBndRecovery ) {
1725   //   cmd += " -C";
1726   // }
1727
1728   // to use FEM correction
1729   // if ( fem && hyp && hyp->myToUseFemCorrection) {
1730   //   cmd += " -FEM";
1731   // }
1732
1733   // to remove initial central point.
1734   if ( rem && hyp && hyp->myToRemoveCentralPoint ) {
1735     if ( forExecutable )
1736       cmd += " --no_initial_central_point";
1737     else
1738       cmd += " --centralpoint no";
1739   }
1740
1741   // options as text
1742   // if ( hyp && !hyp->myTextOption.empty() ) {
1743   //   cmd += " " + hyp->myTextOption;
1744   // }
1745
1746   // min/max size
1747   if ( hyp )
1748   {
1749     if ( hyp->GetMinSize() > 0 )
1750       cmd += " --min_size " + SMESH_Comment( hyp->GetMinSize() );
1751     if ( hyp->GetMaxSize() > 0 )
1752       cmd += " --max_size " + SMESH_Comment( hyp->GetMaxSize() );
1753   }
1754
1755   // to define volumic gradation.
1756   if ( gra && hyp )
1757   {
1758     cmd += " --gradation " + SMESH_Comment( hyp->myGradation );
1759   }
1760
1761   if ( hyp )
1762   {
1763     // proximity
1764     if ( hyp->GetUseVolumeProximity() )
1765     {
1766       cmd += " --volume_proximity_layers " + SMESH_Comment( hyp->GetNbVolumeProximityLayers() );
1767     }
1768
1769     std::string option, value;
1770     bool isDefault;
1771     const TOptionValues* options[] = { & hyp->_option2value, & hyp->_customOption2value };
1772     for ( int iOp = 0; iOp < 2; ++iOp )
1773     {
1774       TOptionValues::const_iterator o2v = options[iOp]->begin();
1775       for ( ; o2v != options[iOp]->end(); ++o2v )
1776       {
1777         option = o2v->first;
1778         value = hyp->GetOptionValue( option, &isDefault );
1779
1780         if ( isDefault )
1781           continue;
1782         if ( value.empty() )//value == NoValue() )
1783         {
1784           if ( hyp->_defaultOptionValues.count( option ))
1785             continue; // non-custom option with no value
1786           //value.clear();
1787         }
1788         if ( strncmp( "no", option.c_str(), 2 ) == 0 ) // options w/o values: --no_*
1789         {
1790           if ( !value.empty() && ToBool( value ) == false )
1791             continue;
1792           value.clear();
1793         }
1794         if ( option[0] != '-' )
1795           cmd += " --";
1796         else
1797           cmd += " ";
1798         cmd += option + " " + value;
1799       }
1800     }
1801   }
1802
1803 #ifdef WIN32
1804   cmd += " < NUL";
1805 #endif
1806
1807   return cmd;
1808 }
1809
1810 //================================================================================
1811 /*!
1812  * \brief Return a unique file name
1813  */
1814 //================================================================================
1815
1816 std::string GHS3DPlugin_Hypothesis::GetFileName(const GHS3DPlugin_Hypothesis* hyp)
1817 {
1818   std::string aTmpDir = hyp ? hyp->GetWorkingDirectory() : DefaultWorkingDirectory();
1819   if ( !SMESH_File( aTmpDir ).exists() )
1820     aTmpDir = Kernel_Utils::GetTmpDirByPath( aTmpDir );
1821
1822   const char lastChar = *aTmpDir.rbegin();
1823 #ifdef WIN32
1824     if(lastChar != '\\') aTmpDir+='\\';
1825 #else
1826     if(lastChar != '/') aTmpDir+='/';
1827 #endif      
1828
1829   TCollection_AsciiString aGenericName = (char*)aTmpDir.c_str();
1830   aGenericName += "GHS3D_";
1831   aGenericName += getpid();
1832   aGenericName += "_";
1833   aGenericName += Abs((Standard_Integer)(long) aGenericName.ToCString());
1834
1835   return aGenericName.ToCString();
1836 }
1837
1838 //================================================================================
1839 /*
1840  * Return the name of executable
1841  */
1842 //================================================================================
1843
1844 std::string GHS3DPlugin_Hypothesis::GetExeName()
1845 {
1846   return "mg-tetra.exe";
1847 }
1848
1849 //================================================================================
1850 /*!
1851 * \brief Return the enforced vertices
1852 */
1853 //================================================================================
1854
1855 GHS3DPlugin_Hypothesis::TGHS3DEnforcedVertexList GHS3DPlugin_Hypothesis::GetEnforcedVertices(const GHS3DPlugin_Hypothesis* hyp)
1856 {
1857   return hyp ? hyp->_GetEnforcedVertices(): TGHS3DEnforcedVertexList();
1858 }
1859
1860 GHS3DPlugin_Hypothesis::TGHS3DEnforcedVertexCoordsValues GHS3DPlugin_Hypothesis::GetEnforcedVerticesCoordsSize (const GHS3DPlugin_Hypothesis* hyp)
1861 {  
1862   return hyp ? hyp->_GetEnforcedVerticesCoordsSize(): TGHS3DEnforcedVertexCoordsValues();
1863 }
1864
1865 GHS3DPlugin_Hypothesis::TGHS3DEnforcedVertexEntryValues GHS3DPlugin_Hypothesis::GetEnforcedVerticesEntrySize (const GHS3DPlugin_Hypothesis* hyp)
1866 {  
1867   return hyp ? hyp->_GetEnforcedVerticesEntrySize(): TGHS3DEnforcedVertexEntryValues();
1868 }
1869
1870 GHS3DPlugin_Hypothesis::TCoordsGHS3DEnforcedVertexMap GHS3DPlugin_Hypothesis::GetEnforcedVerticesByCoords (const GHS3DPlugin_Hypothesis* hyp)
1871 {  
1872   return hyp ? hyp->_GetEnforcedVerticesByCoords(): TCoordsGHS3DEnforcedVertexMap();
1873 }
1874
1875 GHS3DPlugin_Hypothesis::TGeomEntryGHS3DEnforcedVertexMap GHS3DPlugin_Hypothesis::GetEnforcedVerticesByEntry (const GHS3DPlugin_Hypothesis* hyp)
1876 {  
1877   return hyp ? hyp->_GetEnforcedVerticesByEntry(): TGeomEntryGHS3DEnforcedVertexMap();
1878 }
1879
1880 GHS3DPlugin_Hypothesis::TIDSortedNodeGroupMap GHS3DPlugin_Hypothesis::GetEnforcedNodes(const GHS3DPlugin_Hypothesis* hyp)
1881 {
1882   return hyp ? hyp->_GetEnforcedNodes():TIDSortedNodeGroupMap();
1883 }
1884
1885 GHS3DPlugin_Hypothesis::TIDSortedElemGroupMap GHS3DPlugin_Hypothesis::GetEnforcedEdges(const GHS3DPlugin_Hypothesis* hyp)
1886 {
1887   return hyp ? hyp->_GetEnforcedEdges():TIDSortedElemGroupMap();
1888 }
1889
1890 GHS3DPlugin_Hypothesis::TIDSortedElemGroupMap GHS3DPlugin_Hypothesis::GetEnforcedTriangles(const GHS3DPlugin_Hypothesis* hyp)
1891 {
1892   return hyp ? hyp->_GetEnforcedTriangles():TIDSortedElemGroupMap();
1893 }
1894
1895 GHS3DPlugin_Hypothesis::TID2SizeMap GHS3DPlugin_Hypothesis::GetNodeIDToSizeMap(const GHS3DPlugin_Hypothesis* hyp)
1896 {
1897   return hyp ? hyp->_GetNodeIDToSizeMap(): TID2SizeMap();
1898 }
1899
1900 GHS3DPlugin_Hypothesis::TSetStrings GHS3DPlugin_Hypothesis::GetGroupsToRemove(const GHS3DPlugin_Hypothesis* hyp)
1901 {
1902   return hyp ? hyp->_GetGroupsToRemove(): TSetStrings();
1903 }
1904
1905
1906 //=============================================================================
1907 void GHS3DPlugin_Hypothesis::SetOptionValue(const std::string& optionName,
1908                                             const std::string& optionValue)
1909 {
1910   TOptionValues::iterator op_val = _option2value.find(optionName);
1911   if (op_val == _option2value.end())
1912   {
1913     op_val = _customOption2value.find( optionName );
1914     if ( op_val != _customOption2value.end() && op_val->second != optionValue )
1915       NotifySubMeshesHypothesisModification();
1916     _customOption2value[ optionName ] = optionValue;
1917     return;
1918   }
1919
1920   if (op_val->second != optionValue)
1921   {
1922     const char* ptr = optionValue.c_str();
1923     // strip white spaces
1924     while (ptr[0] == ' ')
1925       ptr++;
1926     size_t i = strlen(ptr);
1927     while (i != 0 && ptr[i - 1] == ' ')
1928       i--;
1929     // check value type
1930     bool typeOk = true;
1931     std::string typeName;
1932     if (i == 0) {
1933       // empty string
1934     } else if (_charOptions.count(optionName)) {
1935       // do not check strings
1936     } else if (_doubleOptions.count(optionName)) {
1937       // check if value is double
1938       ToDbl(ptr, &typeOk);
1939       typeName = "real";
1940     } else if (_boolOptions.count(optionName)) {
1941       // check if value is bool
1942       ToBool(ptr, &typeOk);
1943       typeName = "bool";
1944     } else {
1945       // check if value is int
1946       ToInt(ptr, &typeOk);
1947       typeName = "integer";
1948     }
1949     if ( typeOk ) // check some specific values ?
1950     {
1951     }
1952     if ( !typeOk )
1953     {
1954       std::string msg = "Advanced option '" + optionName + "' = '" + optionValue + "' but must be " + typeName;
1955       throw std::invalid_argument(msg);
1956     }
1957     std::string value( ptr, i );
1958     if ( _defaultOptionValues[ optionName ] == value )
1959       value.clear();
1960
1961     op_val->second = value;
1962
1963     NotifySubMeshesHypothesisModification();
1964   }
1965 }
1966
1967 //=============================================================================
1968 //! Return option value. If isDefault provided, it can be a default value,
1969 //  then *isDefault == true. If isDefault is not provided, the value will be
1970 //  empty if it equals a default one.
1971 std::string GHS3DPlugin_Hypothesis::GetOptionValue(const std::string& optionName,
1972                                                    bool*              isDefault) const
1973 {
1974   TOptionValues::const_iterator op_val = _option2value.find(optionName);
1975   if (op_val == _option2value.end())
1976   {
1977     op_val = _customOption2value.find(optionName);
1978     if (op_val == _customOption2value.end())
1979     {
1980       std::string msg = "Unknown MG-Tetra option: <" + optionName + ">";
1981       throw std::invalid_argument(msg);
1982     }
1983   }
1984   std::string val = op_val->second;
1985   if ( isDefault ) *isDefault = ( val.empty() );
1986
1987   if ( val.empty() && isDefault )
1988   {
1989     op_val = _defaultOptionValues.find( optionName );
1990     if (op_val != _defaultOptionValues.end())
1991       val = op_val->second;
1992   }
1993   return val;
1994 }
1995
1996
1997 //=============================================================================
1998 bool GHS3DPlugin_Hypothesis::HasOptionDefined( const std::string& optionName ) const
1999 {
2000   bool isDefault = false;
2001   try
2002   {
2003     GetOptionValue( optionName, &isDefault );
2004   }
2005   catch ( std::invalid_argument& )
2006   {
2007     return false;
2008   }
2009   return !isDefault;
2010 }
2011
2012 //=============================================================================
2013 void GHS3DPlugin_Hypothesis::ClearOption(const std::string& optionName)
2014 {
2015   TOptionValues::iterator op_val = _customOption2value.find(optionName);
2016   if (op_val != _customOption2value.end())
2017    _customOption2value.erase(op_val);
2018   else {
2019     op_val = _option2value.find(optionName);
2020     if (op_val != _option2value.end())
2021       op_val->second.clear();
2022   }
2023 }
2024
2025 //=============================================================================
2026 GHS3DPlugin_Hypothesis::TOptionValues GHS3DPlugin_Hypothesis::GetOptionValues() const
2027 {
2028   TOptionValues vals;
2029   TOptionValues::const_iterator op_val = _option2value.begin();
2030   for ( ; op_val != _option2value.end(); ++op_val )
2031     vals.insert( make_pair( op_val->first, GetOptionValue( op_val->first, GET_DEFAULT() )));
2032
2033   return vals;
2034 }
2035
2036 //================================================================================
2037 /*!
2038  * \brief Converts a string to a bool
2039  */
2040 //================================================================================
2041
2042 bool GHS3DPlugin_Hypothesis::ToBool(const std::string& str, bool* isOk )
2043 {
2044   std::string s = str;
2045   if ( isOk ) *isOk = true;
2046
2047   for ( size_t i = 0; i <= s.size(); ++i )
2048     s[i] = (char) tolower( s[i] );
2049
2050   if ( s == "1" || s == "true" || s == "active" || s == "yes" )
2051     return true;
2052
2053   if ( s == "0" || s == "false" || s == "inactive" || s == "no" )
2054     return false;
2055
2056   if ( isOk )
2057     *isOk = false;
2058   else {
2059     std::string msg = "Not a Boolean value:'" + str + "'";
2060     throw std::invalid_argument(msg);
2061   }
2062   return false;
2063 }
2064
2065 //================================================================================
2066 /*!
2067  * \brief Converts a string to a real value
2068  */
2069 //================================================================================
2070
2071 double GHS3DPlugin_Hypothesis::ToDbl(const std::string& str, bool* isOk )
2072 {
2073   if ( str.empty() ) throw std::invalid_argument("Empty value provided");
2074
2075   char * endPtr;
2076   double val = strtod(&str[0], &endPtr);
2077   bool ok = (&str[0] != endPtr);
2078
2079   if ( isOk ) *isOk = ok;
2080
2081   if ( !ok )
2082   {
2083     std::string msg = "Not a real value:'" + str + "'";
2084     throw std::invalid_argument(msg);
2085   }
2086   return val;
2087 }
2088
2089 //================================================================================
2090 /*!
2091  * \brief Converts a string to a integer value
2092  */
2093 //================================================================================
2094
2095 int GHS3DPlugin_Hypothesis::ToInt(const std::string& str, bool* isOk )
2096 {
2097   if ( str.empty() ) throw std::invalid_argument("Empty value provided");
2098
2099   char * endPtr;
2100   int val = (int)strtol( &str[0], &endPtr, 10);
2101   bool ok = (&str[0] != endPtr);
2102
2103   if ( isOk ) *isOk = ok;
2104
2105   if ( !ok )
2106   {
2107     std::string msg = "Not an integer value:'" + str + "'";
2108     throw std::invalid_argument(msg);
2109   }
2110   return val;
2111 }
2112