Salome HOME
[MEDCalcl] PointSprite and VectorField presentations.
[modules/med.git] / src / MEDCalc / cmp / MEDPresentation.cxx
1 // Copyright (C) 2011-2016  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 // Authors: A Bruneton (CEA), C Aguerre (EdF)
20
21 #include "MEDPyLockWrapper.hxx"
22 #include "MEDFactoryClient.hxx"
23 #include "MEDPresentation.hxx"
24 #include "MEDPresentationException.hxx"
25 #include "MEDCouplingRefCountObject.hxx"
26 #include <SALOME_KernelServices.hxx>
27 #undef LOG
28 #include <Basics_Utils.hxx>
29
30 #include <sstream>
31
32 const std::string MEDPresentation::PROP_NAME  = "name";
33 const std::string MEDPresentation::PROP_NB_COMPONENTS = "nbComponents";
34 const std::string MEDPresentation::PROP_SELECTED_COMPONENT = "selectedComponent";
35 const std::string MEDPresentation::PROP_COMPONENT = "component_";
36 const std::string MEDPresentation::PROP_COLOR_MAP = "colorMap";
37 const std::string MEDPresentation::PROP_SCALAR_BAR_RANGE = "scalarBarRange";
38
39 MEDPresentation::MEDPresentation(MEDPresentation::TypeID fieldHandlerId, const std::string& name,
40                                  const MEDCALC::ViewModeType viewMode,
41                                  const MEDCALC::ColorMapType colorMap,
42                                  const MEDCALC::ScalarBarRangeType sbRange)
43     : _fieldHandlerId(fieldHandlerId), _propertiesStr(),
44       //_pipeline(0), _display(0)
45       _selectedComponentIndex(-1),
46       _viewMode(viewMode),
47       _colorMap(colorMap),
48       _sbRange(sbRange),
49       _renderViewPyId(-1),  // will be set by getRenderViewCommand()
50       _globalDict(0)
51 {
52   MEDCALC::MEDDataManager_ptr dataManager(MEDFactoryClient::getDataManager());
53   MEDCALC::FieldHandler* fieldHandler = dataManager->getFieldHandler(fieldHandlerId);
54   MEDCALC::MeshHandler* meshHandler = dataManager->getMesh(fieldHandler->meshid);
55   MEDCALC::DatasourceHandler* dataSHandler = dataManager->getDatasourceHandlerFromID(meshHandler->sourceid);
56
57   _fileName = dataSHandler->uri;
58   _fieldName = fieldHandler->fieldname;
59   _fieldType = getFieldTypeString((MEDCoupling::TypeOfField) fieldHandler->type);
60   _meshName = meshHandler->name;
61
62   if (_fileName.substr(0, 7) != std::string("file://")) {
63     const char* msg = "MEDPresentation(): Data source is not a file! Can not proceed.";
64     STDLOG(msg);
65     throw MEDPresentationException(msg);
66   }
67   _fileName = _fileName.substr(7, _fileName.size());
68
69   setStringProperty(MEDPresentation::PROP_NAME, name);
70
71   setIntProperty(MEDPresentation::PROP_NB_COMPONENTS, 0);
72   setIntProperty(MEDPresentation::PROP_SELECTED_COMPONENT, 0);
73
74   setIntProperty(MEDPresentation::PROP_COLOR_MAP, static_cast<int>(colorMap));
75   setIntProperty(MEDPresentation::PROP_SCALAR_BAR_RANGE, static_cast<int>(sbRange));
76
77   // Python variables:
78   int id = GeneratePythonId();
79   std::ostringstream oss_o, oss_d, oss_l, oss_s;
80   oss_o << "__obj" << id;
81   oss_s << "__srcObj" << id;
82   oss_d << "__disp" << id;
83   oss_l << "__lut" << id;
84   _objVar = oss_o.str();
85   _srcObjVar = oss_s.str();
86   _dispVar = oss_d.str();
87   _lutVar = oss_l.str();
88 }
89
90 MEDPresentation::~MEDPresentation()
91 {
92   STDLOG("~MEDPresentation(): clear display");
93   {
94     MEDPyLockWrapper lock;
95     std::ostringstream oss_v, oss;
96     oss_v << "__view" << _renderViewPyId;
97     oss << "pvs.Hide(" << _objVar <<  ", view=" << oss_v.str() << ");";
98     oss << "pvs.Render();";
99
100     PyRun_SimpleString(oss.str().c_str());
101   }
102 }
103
104 void
105 MEDPresentation::generatePipeline()
106 {
107   // Might be more complicated in the future:
108
109   this->internalGeneratePipeline();
110 }
111
112 //void
113 //MEDPresentation::pushPyObjects(PyObjectId obj, PyObjectId disp)
114 //{
115 //  _pipeline.push_back(obj);
116 //  _display.push_back(disp);
117 //}
118
119 void
120 MEDPresentation::pushAndExecPyLine(const std::string & lin)
121 {
122   execPyLine(lin);
123   _pythonCmds.push_back(lin);
124 }
125
126 void
127 MEDPresentation::execPyLine(const std::string & lin)
128 {
129   MEDPyLockWrapper lock;
130   STDLOG("@@@@ MEDPresentation::execPyLine() about to exec >> " << lin);
131   if(PyRun_SimpleString(lin.c_str()))
132     {
133       std::ostringstream oss;
134       oss << "MEDPresentation::execPyLine(): following Python command failed!\n";
135       oss << ">> " << lin;
136       STDLOG(oss.str());
137       throw KERNEL::createSalomeException(oss.str().c_str());
138     }
139 }
140
141 void
142 MEDPresentation::setStringProperty(const std::string& propName, const std::string& propValue)
143 {
144   _propertiesStr[propName] = propValue;
145 }
146
147 const std::string
148 MEDPresentation::getStringProperty(const std::string& propName) const
149 {
150   std::map<std::string, std::string>::const_iterator it = _propertiesStr.find(propName);
151   if (it != _propertiesStr.end()) {
152       return (*it).second;
153   }
154   else {
155       STDLOG("MEDPresentation::getStringProperty(): no property named " + propName);
156       throw MEDPresentationException("MEDPresentation::getStringProperty(): no property named " + propName);
157   }
158 }
159
160 void
161 MEDPresentation::setIntProperty(const std::string& propName, const int propValue)
162 {
163   _propertiesInt[propName] = propValue;
164 }
165
166 int
167 MEDPresentation::getIntProperty(const std::string& propName) const
168 {
169   std::map<std::string, int>::const_iterator it = _propertiesInt.find(propName);
170   if (it != _propertiesInt.end()) {
171       return (*it).second;
172   }
173   else {
174       STDLOG("MEDPresentation::getIntProperty(): no property named " + propName);
175       throw MEDPresentationException("MEDPresentation::getIntProperty(): no property named " + propName);
176   }
177 }
178
179  void
180  MEDPresentation::dumpIntProperties() const
181  {
182    std::map<std::string, int>::const_iterator it = _propertiesInt.begin();
183    STDLOG("@@@ Dumping INT properties");
184    for(; it != _propertiesInt.end(); ++it)
185      {
186        std::ostringstream oss;
187        oss << (*it).first << "  ->   " << (*it).second;
188        STDLOG(oss.str());
189      }
190  }
191
192  void
193  MEDPresentation::dumpStringProperties() const
194  {
195    std::map<std::string, std::string>::const_iterator it = _propertiesStr.begin();
196    STDLOG("@@@ Dumping STR properties");
197    for(; it != _propertiesStr.end(); ++it)
198      {
199        std::ostringstream oss;
200        oss << (*it).first << "  ->   " << (*it).second;
201        STDLOG(oss.str());
202      }
203  }
204
205  void
206  MEDPresentation::internalGeneratePipeline()
207  {
208    MEDPyLockWrapper lock;
209    pushAndExecPyLine( "import pvsimple as pvs;");
210  }
211
212
213 /**
214 * @return a borrowed reference. Do not DECRREF!
215 */
216 PyObject*
217 MEDPresentation::getPythonObjectFromMain(const char* python_var) const
218 {
219   if (! _globalDict)
220     {
221       // All the calls below returns *borrowed* references
222       PyObject* main_module = PyImport_AddModule((char*)"__main__");
223       _globalDict = PyModule_GetDict(main_module);
224     }
225   return PyDict_GetItemString(_globalDict, python_var);
226 }
227
228 std::string
229 MEDPresentation::getFieldTypeString(MEDCoupling::TypeOfField fieldType) const
230 {
231   switch(fieldType)
232   {
233     case MEDCoupling::ON_CELLS:
234       return "CELLS";
235     case MEDCoupling::ON_NODES:
236       return "POINTS";
237     default:
238       STDLOG("MEDPresentation::getFieldTypeString() -- Not implemented ! Gauss points?");
239       return "";
240   }
241 }
242
243 std::string
244 MEDPresentation::getRenderViewVar() const
245 {
246   std::ostringstream oss;
247   oss << "__view" << _renderViewPyId;
248   return oss.str();
249 }
250
251 void
252 MEDPresentation::createSource()
253 {
254   std::ostringstream oss;
255   oss << _srcObjVar << " = pvs.MEDReader(FileName='" << _fileName << "');";
256   pushAndExecPyLine(oss.str()); oss.str("");
257   oss << _srcObjVar << ".GenerateVectors = 1;";
258   pushAndExecPyLine(oss.str()); oss.str("");
259 }
260
261 void
262 MEDPresentation::setOrCreateRenderView()
263 {
264   std::ostringstream oss2;
265
266   std::string view(getRenderViewVar());
267   oss2 << "pvs._DisableFirstRenderCameraReset();";
268   pushAndExecPyLine(oss2.str()); oss2.str("");
269   if (_viewMode == MEDCALC::VIEW_MODE_OVERLAP) {
270       // this might potentially re-assign to an existing view variable, but this is OK, we
271       // normally reassign exaclty the same RenderView object.
272       oss2 << view << " = pvs.GetActiveViewOrCreate('RenderView');";
273       pushAndExecPyLine(oss2.str()); oss2.str("");
274   } else if (_viewMode == MEDCALC::VIEW_MODE_REPLACE) {
275       // same as above
276       oss2 << view << " = pvs.GetActiveViewOrCreate('RenderView');";
277       pushAndExecPyLine(oss2.str()); oss2.str("");
278       oss2 << "pvs.active_objects.source and pvs.Hide(view=" << view << ");";
279       pushAndExecPyLine(oss2.str()); oss2.str("");
280       oss2 << "pvs.Render();";
281       pushAndExecPyLine(oss2.str()); oss2.str("");
282   } else if (_viewMode == MEDCALC::VIEW_MODE_NEW_LAYOUT) {
283       oss2 <<  "__layout1 = pvs.servermanager.misc.ViewLayout(registrationGroup='layouts');";
284       pushAndExecPyLine(oss2.str()); oss2.str("");
285       oss2 << view << " = pvs.CreateView('RenderView');";
286       pushAndExecPyLine(oss2.str()); oss2.str("");
287   } else if (_viewMode == MEDCALC::VIEW_MODE_SPLIT_VIEW) {
288       oss2 << view << " = pvs.CreateView('RenderView');";
289       pushAndExecPyLine(oss2.str()); oss2.str("");
290   }
291 }
292
293 void
294 MEDPresentation::resetCameraAndRender()
295 {
296   pushAndExecPyLine(getRenderViewVar() + ".ResetCamera();");
297   pushAndExecPyLine("pvs.Render();");
298 }
299
300 void
301 MEDPresentation::selectFieldComponent()
302 {
303   std::ostringstream oss, oss_l;
304   std::string ret;
305
306   if (_selectedComponentIndex != -1)
307     {
308       oss << _lutVar << ".VectorMode = 'Component';";
309       pushAndExecPyLine(oss.str()); oss.str("");
310       oss << _lutVar << ".VectorComponent = " << _selectedComponentIndex << ";";
311       pushAndExecPyLine(oss.str()); oss.str("");
312     }
313   else  // Euclidean norm
314     {
315       oss << _lutVar << ".VectorMode = 'Magnitude';";
316       pushAndExecPyLine(oss.str()); oss.str("");
317     }
318 }
319
320 void
321 MEDPresentation::selectColorMap()
322 {
323   std::ostringstream oss, oss2;
324
325   oss2 << _lutVar << " = pvs.GetColorTransferFunction('" << _fieldName << "');";
326   pushAndExecPyLine(oss2.str());
327
328   switch (_colorMap) {
329   case MEDCALC::COLOR_MAP_BLUE_TO_RED_RAINBOW:
330     oss << _lutVar << ".ApplyPreset('Blue to Red Rainbow',True);";
331     break;
332   case MEDCALC::COLOR_MAP_COOL_TO_WARM:
333     oss << _lutVar << ".ApplyPreset('Cool to Warm',True);";
334     break;
335   default:
336     STDLOG("MEDPresentation::getColorMapCommand(): invalid colormap!");
337     throw KERNEL::createSalomeException("MEDPresentation::getColorMapCommand(): invalid colormap!");
338   }
339   pushAndExecPyLine(oss.str());
340 }
341
342 void
343 MEDPresentation::showObject()
344 {
345   std::ostringstream oss;
346   oss << _dispVar << " = pvs.Show(" << _objVar << ", " << getRenderViewVar() << ");";
347   pushAndExecPyLine(oss.str());
348 }
349
350 void
351 MEDPresentation::showScalarBar()
352 {
353   std::ostringstream oss;
354   oss << _dispVar <<  ".SetScalarBarVisibility(" << getRenderViewVar() << ", True);";
355   pushAndExecPyLine(oss.str());
356 }
357
358 void
359 MEDPresentation::colorBy(const std::string & fieldType)
360 {
361   std::ostringstream oss;
362   oss << "pvs.ColorBy(" << _dispVar << ", ('" << fieldType << "', '" << _fieldName << "'));";
363   pushAndExecPyLine(oss.str());
364 }
365
366 void
367 MEDPresentation::rescaleTransferFunction()
368 {
369   std::string ret;
370   switch(_sbRange)
371   {
372     case MEDCALC::SCALAR_BAR_ALL_TIMESTEPS:
373       ret = _dispVar + ".RescaleTransferFunctionToDataRangeOverTime();";
374       break;
375     case MEDCALC::SCALAR_BAR_CURRENT_TIMESTEP:
376       ret = _dispVar + ".RescaleTransferFunctionToDataRange(False);";
377       break;
378     default:
379       STDLOG("MEDPresentation::getRescaleCommand(): invalid range!");
380       throw KERNEL::createSalomeException("MEDPresentation::getRescaleCommand(): invalid range!");
381   }
382   pushAndExecPyLine(ret);
383 }
384
385 int
386 MEDPresentation::GeneratePythonId()
387 {
388   static int INIT_ID = 0;
389   return INIT_ID++;
390 }
391
392 void
393 MEDPresentation::activateView()
394 {
395   MEDPyLockWrapper lock;
396   pushAndExecPyLine("pvs.SetActiveView(" + getRenderViewVar() + ");");
397 }
398
399
400 std::string
401 MEDPresentation::paravisDump() const
402 {
403   using namespace std;
404   ostringstream oss;
405   for (vector<string>::const_iterator it=_pythonCmds.begin(); it != _pythonCmds.end(); ++it)
406     {
407       oss << (*it);
408       oss << "\n";
409     }
410   return oss.str();
411 }
412
413 /**
414  * Query all available component names for the field associated with this presentation.
415  * Fills in all the corresponding string properties:
416  *  - PROP_COMPONENT1
417  *  - PROP_COMPONENT2
418  *    etc...
419  *  and the number of components.
420  */
421 void
422 MEDPresentation::fillAvailableFieldComponents()
423 {
424   MEDPyLockWrapper lock;  // GIL!
425   std::string typ;
426
427   if(_fieldType == "CELLS") {
428       typ = "CellData";
429   }
430   else if (_fieldType == "POINTS") {
431       typ = "PointData";
432   }
433   else {
434       std::string msg("Unsupported spatial discretisation: " + _fieldType);
435       STDLOG(msg);
436       throw KERNEL::createSalomeException(msg.c_str());
437   }
438
439   std::ostringstream oss;
440   oss << "__nbCompo = " << _srcObjVar << "." << typ << ".GetArray('" <<  _fieldName << "').GetNumberOfComponents();";
441   execPyLine(oss.str());
442   PyObject* p_obj = getPythonObjectFromMain("__nbCompo");
443   long nbCompo;
444   if (p_obj && PyInt_Check(p_obj))
445     nbCompo = PyInt_AS_LONG(p_obj);
446   else
447     {
448       STDLOG("Unexpected Python error");
449       throw KERNEL::createSalomeException("Unexpected Python error");
450     }
451   setIntProperty(MEDPresentation::PROP_NB_COMPONENTS, nbCompo);
452   for (long i = 0; i<nbCompo; i++)
453     {
454       std::ostringstream oss2;
455       oss2 << "__compo = " << _srcObjVar << "." << typ << ".GetArray('" <<  _fieldName << "').GetComponentName(" << i << ");";
456       execPyLine(oss2.str());
457       PyObject* p_obj = getPythonObjectFromMain("__compo");
458       std::string compo;
459       if (p_obj && PyString_Check(p_obj))
460         compo = std::string(PyString_AsString(p_obj));  // pointing to internal Python memory, so make a copy!!
461       else
462         {
463           STDLOG("Unexpected Python error");
464           throw KERNEL::createSalomeException("Unexpected Python error");
465         }
466       std::ostringstream oss_p;
467       oss_p << MEDPresentation::PROP_COMPONENT << i;
468       setStringProperty(oss_p.str(), compo);
469     }
470 }
471
472 /**
473  * In case where a CELLS field needs to be converted to POINT field.
474  * This updates the source object to become the result of the CellDatatoPointData filter.
475  */
476 void
477 MEDPresentation::applyCellToPointIfNeeded()
478 {
479   std::ostringstream oss, oss2;
480   // Apply Cell data to point data:
481   oss2 << "__srcObj" << GeneratePythonId();
482   oss << oss2.str() << " = pvs.CellDatatoPointData(Input=" << _srcObjVar << ");";
483   pushAndExecPyLine(oss.str()); oss.str("");
484   // Now the source becomes the result of the CellDatatoPointData:
485   _srcObjVar = oss2.str();
486 }
487
488 /**
489  * Convert a vector field into a 3D vector field:
490  *  - if the vector field is already 3D, nothing to do
491  *  - if it is 2D, then add a null component
492  *  - otherwise (tensor field, scalar field) throw
493  */
494 void
495 MEDPresentation::convertTo3DVectorField()
496 {
497   std::ostringstream oss, oss1, oss2, oss3;
498
499   int nbCompo = getIntProperty(MEDPresentation::PROP_NB_COMPONENTS);
500   if (nbCompo < 2 || nbCompo > 3)
501     {
502       oss << "The field '" << _fieldName << "' must have 2 or 3 components for this presentation!";
503       STDLOG(oss.str());
504       throw KERNEL::createSalomeException(oss.str().c_str());
505     }
506   if (nbCompo == 3)
507     return;
508
509   // Apply calculator:
510   oss2 << "__srcObj" << GeneratePythonId();
511   oss << oss2.str() << " = pvs.Calculator(Input=" << _srcObjVar << ");";
512   pushAndExecPyLine(oss.str()); oss.str("");
513   // Now the source becomes the result of the CellDatatoPointData:
514   _srcObjVar = oss2.str();
515   std::string typ;
516   if(_fieldType == "CELLS")
517     typ = "Cell Data";
518   else if(_fieldType == "POINTS")
519     typ = "Point Data";
520   else
521     {
522       oss3 << "Field '" << _fieldName << "' has invalid field type";
523       STDLOG(oss3.str());
524       throw KERNEL::createSalomeException(oss3.str().c_str());
525     }
526   oss << _srcObjVar << ".AttributeMode = '" <<  typ << "';";
527   pushAndExecPyLine(oss.str()); oss.str("");
528   oss << _srcObjVar << ".ResultArrayName = '" <<  _fieldName << "_CALC';";  // will never be needed I think
529   pushAndExecPyLine(oss.str()); oss.str("");
530   oss << _srcObjVar << ".Function = '" <<  _fieldName << "_0*iHat + " << _fieldName << "_1*jHat + 0.0*zHat';";
531   pushAndExecPyLine(oss.str()); oss.str("");
532 }
533
534 //double
535 //MEDPresentation::computeCellAverageSize()
536 //{
537 //  std::ostringstream oss;
538 //  oss << "import MEDLoader;";
539 //  pushAndExecPyLine(oss.str()); oss.str("");
540 //  oss << "__mesh = MEDLoader.ReadMeshFromFile('" << _fileName << "', '" << _meshName << "');";
541 //  pushAndExecPyLine(oss.str()); oss.str("");
542 //
543 //  oss << "__bb = __mesh.getBoundingBox()";
544 //  pushAndExecPyLine(oss.str()); oss.str("");
545 //  oss << "__deltas = [x[1]-x[0] for x in __bb];";
546 //  pushAndExecPyLine(oss.str()); oss.str("");
547 //  oss << "__vol = reduce(lambda x,y:x*y, __deltas, 1.0);";
548 //  pushAndExecPyLine(oss.str()); oss.str("");
549 //  // Average cell size is the the n-th root of average volume of a cell, with n being the space dimension
550 //  oss << "__cellSize = (__vol/__mesh.getNumberOfCells())**(1.0/len(__bb));";
551 //  pushAndExecPyLine(oss.str()); oss.str("");
552 //
553 //  PyObject * pyObj = getPythonObjectFromMain("__cellSize");
554 //  bool err = false;
555 //  if (!pyObj || !PyFloat_Check(pyObj)) {  /* nothing to do, err handler below */}
556 //  else {
557 //      double ret= PyFloat_AsDouble(pyObj);
558 //      if(!PyErr_Occurred())
559 //        return ret;
560 //    }
561 //  // From here, an error for sure.
562 //  const char * msg = "MEDPresentation::computeCellAverageSize(): Python error.";
563 //  STDLOG(msg);
564 //  throw KERNEL::createSalomeException(msg);
565 //}