1 // Copyright (C) 2011-2023 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 // Authors: A Bruneton (CEA), C Aguerre (EdF)
22 #include "MEDPyLockWrapper.hxx"
23 #include "MEDFactoryClient.hxx"
24 #include "MEDPresentation.hxx"
25 #include "MEDPresentationException.hxx"
26 #include "MEDCouplingRefCountObject.hxx"
27 #include <SALOME_KernelServices.hxx>
29 #include <Basics_Utils.hxx>
33 #if PY_VERSION_HEX < 0x03050000
35 Py_EncodeLocale(const wchar_t *text, size_t *error_pos)
37 return _Py_wchar2char(text, error_pos);
41 const std::string MEDPresentation::PROP_NAME = "name";
42 const std::string MEDPresentation::PROP_NB_COMPONENTS = "nbComponents";
43 const std::string MEDPresentation::PROP_SELECTED_COMPONENT = "selectedComponent";
44 const std::string MEDPresentation::PROP_COMPONENT = "component_";
45 const std::string MEDPresentation::PROP_COLOR_MAP = "colorMap";
46 const std::string MEDPresentation::PROP_SCALAR_BAR_RANGE = "scalarBarRange";
47 const std::string MEDPresentation::PROP_VISIBILITY = "visibility";
48 const std::string MEDPresentation::PROP_SCALAR_BAR_VISIBILITY = "scalarBarVisibility";
49 const std::string MEDPresentation::PROP_SCALAR_BAR_MIN_VALUE = "scalarBarMinValue";
50 const std::string MEDPresentation::PROP_SCALAR_BAR_MAX_VALUE = "scalarBarMaxValue";
51 const std::string MEDPresentation::PROP_HIDE_DATA_OUTSIDE_CUSTOM_RANGE = "hideDataOutsideCustomRange";
53 #define PROGRAMMABLE "__programmable"
55 MEDPresentation::MEDPresentation(MEDPresentation::TypeID handlerId, const std::string& name,
56 const MEDCALC::ViewModeType viewMode,
57 const MEDCALC::ColorMapType colorMap,
58 const MEDCALC::ScalarBarRangeType sbRange)
59 : _meshName(""), _fileName(""), _fieldName(""),
60 _mcFieldType(MEDCoupling::ON_CELLS),
62 _handlerId(handlerId),
63 _selectedComponentIndex(-1),
67 _renderViewPyId(-1), // will be set by MEDPresentationManager_i::_makePresentation()
69 _presentationVisibility(true),
70 _scalarBarVisibility(true),
71 _scalarBarRangeArray{ 0.0, 100.0 },
72 _programmableInitialized(false),
73 _hideDataOutsideCustomRange(false),
75 _nbComponentsInThresholdInput(0)
77 setStringProperty(MEDPresentation::PROP_NAME, name);
79 setIntProperty(MEDPresentation::PROP_NB_COMPONENTS, 0);
80 setIntProperty(MEDPresentation::PROP_SELECTED_COMPONENT, 0);
82 setIntProperty(MEDPresentation::PROP_COLOR_MAP, static_cast<int>(colorMap));
83 setIntProperty(MEDPresentation::PROP_SCALAR_BAR_RANGE, static_cast<int>(sbRange));
84 setIntProperty(MEDPresentation::PROP_VISIBILITY, static_cast<int>(_presentationVisibility));
85 setIntProperty(MEDPresentation::PROP_SCALAR_BAR_VISIBILITY, static_cast<int>(_scalarBarVisibility));
86 setDoubleProperty(MEDPresentation::PROP_SCALAR_BAR_MIN_VALUE, _scalarBarRangeArray[0]);
87 setDoubleProperty(MEDPresentation::PROP_SCALAR_BAR_MAX_VALUE, _scalarBarRangeArray[1]);
88 setIntProperty(MEDPresentation::PROP_HIDE_DATA_OUTSIDE_CUSTOM_RANGE, static_cast<int>(_hideDataOutsideCustomRange));
92 int id = GeneratePythonId();
93 std::ostringstream oss_o, oss_d, oss_l, oss_s, oss_r, oss_cl, oss_p;
94 oss_o << "__obj" << id;
95 oss_s << "__srcObj" << id;
96 oss_d << "__disp" << id;
97 oss_l << "__lut" << id;
98 oss_r << "__range" << id;
99 oss_p << PROGRAMMABLE << id;
100 _objVar = oss_o.str();
101 _srcObjVar = oss_s.str();
102 _dispVar = oss_d.str();
103 _lutVar = oss_l.str();
104 _rangeVar = oss_r.str();
105 _programmableVar = oss_p.str();
109 * For most of the presentations the field name etc is required.
110 * For the MEDPresentationMeshView however, the handler ID is a mesh handler ID, not a field, and the
111 * treatment is specific.
114 MEDPresentation::initFieldMeshInfos()
116 MEDCALC::MEDDataManager_ptr dataManager(MEDFactoryClient::getDataManager());
117 MEDCALC::FieldHandler* fieldHandler = dataManager->getFieldHandler(_handlerId);
118 MEDCALC::MeshHandler* meshHandler = dataManager->getMeshHandler(fieldHandler->meshid);
119 //MEDCALC::DatasourceHandler* dataSHandler = dataManager->getDatasourceHandlerFromID(meshHandler->sourceid); // todo: unused
121 // get the file name of the field (or its memory information)
122 extractFileName(std::string(fieldHandler->source));
124 _fieldName = fieldHandler->fieldname;
125 _mcFieldType = (MEDCoupling::TypeOfField) fieldHandler->type;
126 _pvFieldType = getPVFieldTypeString(_mcFieldType);
127 _colorByType = _pvFieldType; // by default the same; overridden in DeflectionShape, VectorField, PointSprite and Contour, Plot3D
128 _meshName = meshHandler->name;
132 MEDPresentation::extractFileName(const std::string& name)
134 STDLOG("MEDPresentation::extractFileName('" << name << "')");
136 if (_fileName.substr(0, 7) != std::string("file://")) {
137 STDLOG("MEDPresentation(): Data source is in memory! Saving it in tmp file.");
138 // export a med file with this field
139 // we could instead use CORBA to transfer the field to PARAVIS like in MEDCalculatorDBFieldReal::display()
140 _fileName = std::tmpnam(NULL);
141 MEDCALC::FieldIdList fieldIdList;
142 fieldIdList.length(1);
143 fieldIdList[0] = _handlerId;
144 MEDFactoryClient::getDataManager()->saveFields(_fileName.c_str(), fieldIdList);
147 // removing "file://"
148 _fileName = _fileName.substr(7, _fileName.size());
149 STDLOG("MEDPresentation::extractFileName _fileName=" << _fileName);
152 MEDPresentation::~MEDPresentation()
154 STDLOG("~MEDPresentation(): clear display");
156 MEDPyLockWrapper lock;
157 std::ostringstream oss;
160 oss << "pvs.Hide(" << _objVar << ", view=" << getRenderViewVar() << ");";
161 for (auto& value : _presentationThresolds) {
163 oss << "pvs.Hide(" << value._thresholdVar << ", view=" << getRenderViewVar() << ");";
166 execPyLine(oss.str());
167 // :TRICKY: The two following lines raise an exception when closing MED module
168 // after sequence: MED - load file - PARAVIS - MED - close SALOME
169 // (see Mantis #23461)
170 //execPyLine(getRenderViewVar() + ".ResetCamera();");
171 //execPyLine("pvs.Render();");
173 catch(SALOME::SALOME_Exception&) {
179 MEDPresentation::generatePipeline()
181 // Might be more complicated in the future:
183 this->internalGeneratePipeline();
186 void MEDPresentation::internalGenerateThreshold() {
187 std::ostringstream oss;
188 std::string inputFieldName = getFieldName();
189 if (!_programmableInitialized) {
190 if (_nbComponentsInThresholdInput > 1) {
191 std::string typ = toScriptCellType(_colorByType);
192 oss << _programmableVar << " = pvs.ProgrammableFilter(Input = " << _objVar << ");";
193 oss << _programmableVar << ".Script = \"\"\"import numpy as np" << std::endl;
194 oss << "import paraview.vtk.numpy_interface.dataset_adapter as dsa" << std::endl;
195 oss << "input0 = inputs[0]" << std::endl;
196 oss << "inputDataArray=input0." << typ << "['" << inputFieldName << "']" << std::endl;
197 oss << "if type(inputDataArray) == dsa.VTKCompositeDataArray:" << std::endl;
198 oss << "\tnpa = inputDataArray.GetArrays()" << std::endl;
199 oss << "else:" << std::endl;
200 oss << "\tnpa = inputDataArray" << std::endl;
201 oss << "if type(npa) == list:" << std::endl;
202 oss << "\tarrs = []" << std::endl;
203 oss << "\tfor a in npa:" << std::endl;
204 oss << "\t\tmgm = np.linalg.norm(a, axis = -1)" << std::endl;
205 oss << "\t\tmga = mgm.reshape(mgm.size, 1)" << std::endl;
206 oss << "\t\tarrs.append(mga)" << std::endl;
207 oss << "\tca = dsa.VTKCompositeDataArray(arrs)" << std::endl;
208 oss << "\toutput." << typ << ".append(ca, '" << inputFieldName << "_magnitude')" << std::endl;
209 oss << "else:" << std::endl;
210 oss << "\tmgm = np.linalg.norm(npa, axis = -1)" << std::endl;
211 oss << "\tmga = mgm.reshape(mgm.size, 1)" << std::endl;
212 oss << "\toutput." << typ << ".append(mga, '" << inputFieldName << "_magnitude')" << std::endl;
213 for (std::vector<std::string>::size_type ii = 1; ii < _nbComponentsInThresholdInput + 1 ; ii++) {
214 oss << "dataArray" << ii << " = inputDataArray[:, [" << ii - 1 << "]]" << std::endl;
215 oss << "output." << typ << ".append(dataArray" << ii << ", '" << inputFieldName << "_" << ii << "')" << std::endl;
217 oss << "\"\"\"" << std::endl;
218 _programmableInitialized = true;
222 ComponentThresold& currentThreshold = _presentationThresolds[getThresholdIndex()];
223 if (!currentThreshold._thresholdInitialized) {
224 std::string& thInput = (_nbComponentsInThresholdInput > 1 ) ? _programmableVar : _objVar;
225 std::string arrayName = getThresholdFieldName();
226 oss << currentThreshold._thresholdVar << " = pvs.Threshold(Input = " << thInput << ");";
227 oss << currentThreshold._thresholdVar << ".Scalars = ['" << _colorByType << "', '" << arrayName << "'];";
228 oss << additionalThresholdInitializationActions();
229 oss << currentThreshold._thresholdDispVar << " = pvs.Show(" << currentThreshold._thresholdVar << ", "
230 << getRenderViewVar() << ");";
231 oss << currentThreshold._thresholdLutVar << " = pvs.GetColorTransferFunction('" << arrayName << "', "
232 << currentThreshold._thresholdDispVar << ", separate=True);";
233 oss << "pvs.ColorBy(" << currentThreshold._thresholdDispVar << ", ('" << _colorByType << "', '"
234 << arrayName << "'), separate = True);";
235 oss << additionalThresholdVisualizationActions();
236 currentThreshold._thresholdInitialized = true;
238 if (oss.str().length() > 0) {
239 pushAndExecPyLine(oss.str());
244 //MEDPresentation::pushPyObjects(PyObjectId obj, PyObjectId disp)
246 // _pipeline.push_back(obj);
247 // _display.push_back(disp);
251 MEDPresentation::pushAndExecPyLine(const std::string & lin)
254 _pythonCmds.push_back(lin);
258 MEDPresentation::execPyLine(const std::string & lin)
260 MEDPyLockWrapper lock;
261 STDLOG("@@@@ MEDPresentation::execPyLine() about to exec >> " << lin);
262 if(PyRun_SimpleString(lin.c_str()))
264 std::ostringstream oss;
265 oss << "MEDPresentation::execPyLine(): following Python command failed!\n";
268 throw KERNEL::createSalomeException(oss.str().c_str());
273 MEDPresentation::setStringProperty(const std::string& propName, const std::string& propValue)
275 _propertiesStr[propName] = propValue;
279 MEDPresentation::getStringProperty(const std::string& propName) const
281 std::map<std::string, std::string>::const_iterator it = _propertiesStr.find(propName);
282 if (it != _propertiesStr.end()) {
286 STDLOG("MEDPresentation::getStringProperty(): no property named " + propName);
287 throw MEDPresentationException("MEDPresentation::getStringProperty(): no property named " + propName);
292 MEDPresentation::setIntProperty(const std::string& propName, const int propValue)
294 _propertiesInt[propName] = propValue;
298 MEDPresentation::getIntProperty(const std::string& propName) const
300 std::map<std::string, int>::const_iterator it = _propertiesInt.find(propName);
301 if (it != _propertiesInt.end()) {
305 STDLOG("MEDPresentation::getIntProperty(): no property named " + propName);
306 throw MEDPresentationException("MEDPresentation::getIntProperty(): no property named " + propName);
311 MEDPresentation::dumpIntProperties() const
313 std::map<std::string, int>::const_iterator it = _propertiesInt.begin();
314 STDLOG("@@@ Dumping INT properties");
315 for(; it != _propertiesInt.end(); ++it)
317 std::ostringstream oss;
318 oss << (*it).first << " -> " << (*it).second;
324 MEDPresentation::setDoubleProperty(const std::string& propName, const double propValue)
326 _propertiesDouble[propName] = propValue;
330 MEDPresentation::getDoubleProperty(const std::string& propName) const
332 std::map<std::string, double>::const_iterator it = _propertiesDouble.find(propName);
333 if (it != _propertiesDouble.end()) {
337 STDLOG("MEDPresentation::getDoubleProperty(): no property named " + propName);
338 throw MEDPresentationException("MEDPresentation::getDoubleProperty(): no property named " + propName);
343 MEDPresentation::dumpDoubleProperties() const
345 std::map<std::string, double>::const_iterator it = _propertiesDouble.begin();
346 STDLOG("@@@ Dumping DOUBLE properties");
347 for (; it != _propertiesDouble.end(); ++it)
349 std::ostringstream oss;
350 oss << (*it).first << " -> " << (*it).second;
356 MEDPresentation::dumpStringProperties() const
358 std::map<std::string, std::string>::const_iterator it = _propertiesStr.begin();
359 STDLOG("@@@ Dumping STR properties");
360 for(; it != _propertiesStr.end(); ++it)
362 std::ostringstream oss;
363 oss << (*it).first << " -> " << (*it).second;
369 MEDPresentation::internalGeneratePipeline()
371 MEDPyLockWrapper lock;
372 pushAndExecPyLine( "import pvsimple as pvs;");
373 pushAndExecPyLine( "import medcalc");
378 * @return a borrowed reference. Do not DECRREF!
381 MEDPresentation::getPythonObjectFromMain(const char* python_var) const
385 // All the calls below returns *borrowed* references
386 PyObject* main_module = PyImport_AddModule((char*)"__main__");
387 _globalDict = PyModule_GetDict(main_module);
389 return PyDict_GetItemString(_globalDict, python_var);
393 MEDPresentation::getPVFieldTypeString(MEDCoupling::TypeOfField fieldType) const
397 case MEDCoupling::ON_CELLS:
399 case MEDCoupling::ON_NODES:
401 case MEDCoupling::ON_GAUSS_PT:
402 return "POINTS"; // because internally after application of the ELGA filter, the field will appear as a POINT field
403 case MEDCoupling::ON_GAUSS_NE:
404 return "POINTS"; // because internally after application of the ELNO mesh filter, the field will appear as a POINT field
406 STDLOG("MEDPresentation::getPVFieldTypeString() -- Not implemented ! ELNO field?");
412 MEDPresentation::getRenderViewVar() const
414 std::ostringstream oss;
415 oss << "__view" << _renderViewPyId;
420 * Creates the MEDReader source in the pipeline, and potentially apply GAUSS/ELNO filters.
423 MEDPresentation::createSource()
426 switch(_mcFieldType) {
427 case MEDCoupling::ON_CELLS: typ = "P0"; break;
428 case MEDCoupling::ON_NODES: typ = "P1"; break;
429 case MEDCoupling::ON_GAUSS_PT: typ = "GAUSS"; break;
430 case MEDCoupling::ON_GAUSS_NE: typ = "GSSNE"; break;
432 const char * msg ="MEDPresentation::createSource(): field type not impl. yet!";
434 throw KERNEL::createSalomeException(msg);
437 std::ostringstream oss;
438 oss << _srcObjVar << " = pvs.MEDReader(FileNames=r'" << _fileName << "');";
439 pushAndExecPyLine(oss.str()); oss.str("");
440 oss << "medcalc.SelectSourceField(" << _srcObjVar << ", '" << _meshName << "', '"
441 << _fieldName << "', '" << typ << "');";
442 pushAndExecPyLine(oss.str()); oss.str("");
443 // Generate complete vector fields: fields with 2 components will copied into <name>_vector and
444 // have a third null component added.
445 oss << _srcObjVar << ".VectorsProperty = 1;";
446 pushAndExecPyLine(oss.str()); oss.str("");
448 // Make sure this is set so we stick to time steps:
449 pushAndExecPyLine("pvs.GetAnimationScene().PlayMode = 'Snap To TimeSteps'");
451 // Deal with GAUSS fields:
452 if(_mcFieldType == MEDCoupling::ON_GAUSS_PT)
454 std::ostringstream oss, oss2;
455 oss2 << "__srcObj" << GeneratePythonId();
456 oss << oss2.str() << " = pvs.ELGAfieldToPointGaussian(Input=" << _srcObjVar << ");";
457 pushAndExecPyLine(oss.str()); oss.str("");
458 // Now the source becomes the result of the CellDatatoPointData:
459 _srcObjVar = oss2.str();
460 oss << _srcObjVar << ".SelectSourceArray = ['CELLS', 'ELGA@0'];";
461 pushAndExecPyLine(oss.str()); oss.str("");
463 if(_mcFieldType == MEDCoupling::ON_GAUSS_NE)
465 std::ostringstream oss, oss2;
466 oss2 << "__srcObj" << GeneratePythonId();
467 oss << oss2.str() << " = pvs.ELNOfieldToSurface(Input=" << _srcObjVar << ");";
468 pushAndExecPyLine(oss.str()); oss.str("");
469 // Now the source becomes the result of the CellDatatoPointData:
470 _srcObjVar = oss2.str();
475 * Set the timestamp of the animation to the timestamp of the field.
476 * Especially useful when working on a field's iteration:
477 * in the workspace, in the python console, or using changeUnderlyingMesh.
480 MEDPresentation::setTimestamp()
482 // get the timestamp of the field
483 double timestamp = MEDFactoryClient::getDataManager()->getFieldTimestamp(_handlerId);
484 STDLOG("Displaying timestamp : " << timestamp);
486 std::ostringstream oss;
488 // go to the right timestamp in animation (view and VCR toolbar)
489 pushAndExecPyLine("pvs.GetAnimationScene().UpdateAnimationUsingDataTimeSteps()");
490 oss << "pvs.GetAnimationScene().AnimationTime = " << timestamp << ";";
491 pushAndExecPyLine(oss.str()); oss.str("");
492 oss << "pvs.GetTimeKeeper().Time = " << timestamp << ";";
493 pushAndExecPyLine(oss.str()); oss.str("");
497 MEDPresentation::setOrCreateRenderView()
499 std::ostringstream oss2;
501 std::string view(getRenderViewVar());
502 oss2 << "pvs._DisableFirstRenderCameraReset();";
503 pushAndExecPyLine(oss2.str()); oss2.str("");
504 if (_viewMode == MEDCALC::VIEW_MODE_OVERLAP) {
505 // this might potentially re-assign to an existing view variable, but this is OK, we
506 // normally reassign exactly the same RenderView object.
507 oss2 << view << " = medcalc.FindOrCreateView('RenderView');";
508 pushAndExecPyLine(oss2.str()); oss2.str("");
509 } else if (_viewMode == MEDCALC::VIEW_MODE_REPLACE) {
511 oss2 << view << " = medcalc.FindOrCreateView('RenderView');";
512 pushAndExecPyLine(oss2.str()); oss2.str("");
513 oss2 << "pvs.active_objects.source and pvs.Hide(view=" << view << ");";
514 pushAndExecPyLine(oss2.str()); oss2.str("");
515 oss2 << "pvs.Render();";
516 pushAndExecPyLine(oss2.str()); oss2.str("");
517 } else if (_viewMode == MEDCALC::VIEW_MODE_NEW_LAYOUT) {
518 oss2 << "nbLayouts = len(pvs.GetLayouts());";
519 pushAndExecPyLine(oss2.str()); oss2.str("");
520 oss2 << "__layout1 = pvs.CreateLayout('Layout #%i'%(nbLayouts+1));";
521 pushAndExecPyLine(oss2.str()); oss2.str("");
522 oss2 << view << " = pvs.CreateView('RenderView');";
523 pushAndExecPyLine(oss2.str()); oss2.str("");
524 oss2 << "pvs.AssignViewToLayout(view=" << view << ", layout=__layout1, hint=0);";
525 pushAndExecPyLine(oss2.str()); oss2.str("");
526 } else if (_viewMode == MEDCALC::VIEW_MODE_SPLIT_VIEW) {
527 oss2 << "__activeLayout = pvs.GetLayout();";
528 pushAndExecPyLine(oss2.str()); oss2.str("");
529 oss2 << "__activeLayout.SplitHorizontal(0, 0.5);";
530 pushAndExecPyLine(oss2.str()); oss2.str("");
531 oss2 << view << " = pvs.CreateView('RenderView');";
532 pushAndExecPyLine(oss2.str()); oss2.str("");
533 oss2 << "pvs.AssignViewToLayout(view=" << view << ", layout=__activeLayout, hint=2);";
534 pushAndExecPyLine(oss2.str()); oss2.str("");
539 MEDPresentation::resetCameraAndRender()
541 pushAndExecPyLine(getRenderViewVar() + ".ResetCamera();");
542 pushAndExecPyLine("pvs.Render();");
546 MEDPresentation::selectFieldComponent()
548 std::ostringstream oss, oss_l;
550 if (!_hideDataOutsideCustomRange) {
551 if (_selectedComponentIndex != -1)
553 oss << _lutVar << ".VectorMode = 'Component';";
554 pushAndExecPyLine(oss.str()); oss.str("");
555 oss << _lutVar << ".VectorComponent = " << _selectedComponentIndex << ";";
556 pushAndExecPyLine(oss.str()); oss.str("");
558 else // Euclidean norm
560 oss << _lutVar << ".VectorMode = 'Magnitude';";
561 pushAndExecPyLine(oss.str()); oss.str("");
565 // Make sure that threshold is initialized
566 internalGenerateThreshold();
571 selectColorMap(false);
573 if (!_presentationThresolds[getThresholdIndex()]._active) {
574 std::vector<std::string>::size_type idx = (_nbComponentsInThresholdInput > 1) ? -1 : 0;
575 for (auto& value : _presentationThresolds) {
576 // Hide previous threshold
578 bool currentVisibility = _presentationVisibility;
579 std::vector<std::string>::size_type currentIndex = _selectedComponentIndex;
580 _presentationVisibility = false;
581 _selectedComponentIndex = idx;
583 _selectedComponentIndex = currentIndex;
584 _presentationVisibility = currentVisibility;
585 value._active = false;
589 // Show new threshold
591 _presentationThresolds[getThresholdIndex()]._active = true;
598 * Needs the LUT, so to be called after selectColorMap for the first time.
601 MEDPresentation::scalarBarTitle()
603 // get selected component name:
604 std::string compoName;
605 if (_selectedComponentIndex != -1)
607 std::ostringstream oss1;
608 oss1 << MEDPresentation::PROP_COMPONENT << _selectedComponentIndex;
609 compoName = getStringProperty(oss1.str());
613 if (getIntProperty(MEDPresentation::PROP_NB_COMPONENTS) == 1)
616 compoName = "Magnitude";
618 std::ostringstream oss;
619 if (_hideDataOutsideCustomRange) {
620 oss << "pvs.GetScalarBar(" << getLutVar() << ").Title = '" << _fieldName << "';";
622 oss << "pvs.GetScalarBar(" << getLutVar() << ").ComponentTitle = '" << compoName << "';";
623 pushAndExecPyLine(oss.str()); oss.str("");
627 MEDPresentation::selectColorMap(const bool updateFieldComponent)
629 std::ostringstream oss;
632 case MEDCALC::COLOR_MAP_BLUE_TO_RED_RAINBOW:
633 oss << getLutVar() << ".ApplyPreset('Blue to Red Rainbow',True);";
635 case MEDCALC::COLOR_MAP_COOL_TO_WARM:
636 oss << getLutVar() << ".ApplyPreset('Cool to Warm',True);";
639 STDLOG("MEDPresentation::getColorMapCommand(): invalid colormap!");
640 throw KERNEL::createSalomeException("MEDPresentation::getColorMapCommand(): invalid colormap!");
642 pushAndExecPyLine(oss.str());
644 if(updateFieldComponent) {
645 selectFieldComponent(); // somehow PV keeps the LUT parameters of the previous presentation, so better reset this.
650 MEDPresentation::showObject()
652 std::ostringstream oss;
653 oss << _dispVar << " = pvs.Show(" << _objVar << ", " << getRenderViewVar() << ");";
654 oss << _lutVar << " = pvs.GetColorTransferFunction('" << getFieldName() << "', " << _dispVar << ", separate=True);";
655 pushAndExecPyLine(oss.str());
659 MEDPresentation::hideObject()
661 std::ostringstream oss;
662 oss <<"pvs.Hide(" << _objVar << ", " << getRenderViewVar() << ");";
663 pushAndExecPyLine(oss.str());
667 MEDPresentation::showScalarBar()
669 // Display Scalar Bar only if presentation is visible
670 if (_presentationVisibility) {
671 std::ostringstream oss;
672 oss << getDispVar() << ".SetScalarBarVisibility(" << getRenderViewVar() << ", True);";
673 pushAndExecPyLine(oss.str());
678 MEDPresentation::hideScalarBar()
680 std::ostringstream oss;
681 oss << getDispVar() << ".SetScalarBarVisibility(" << getRenderViewVar() << ", False);";
682 pushAndExecPyLine(oss.str());
686 MEDPresentation::scalarBarVisibility() {
687 _scalarBarVisibility ? showScalarBar() : hideScalarBar();
691 MEDPresentation::colorBy()
693 std::ostringstream oss;
694 oss << "pvs.ColorBy(" << getDispVar() << ", ('" << _colorByType << "', '" << getFieldName() << "'), separate=True);";
695 pushAndExecPyLine(oss.str());
698 void MEDPresentation::visibility() {
699 std::ostringstream oss;
700 oss << getDispVar() << ".Visibility = " << (_presentationVisibility ? "True" : "False") << ";";
701 pushAndExecPyLine(oss.str());
703 // Hide scalar bar with the presentation
704 if (!_presentationVisibility && _scalarBarVisibility)
707 // Show scalar bar with the presentation
708 if (_presentationVisibility && _scalarBarVisibility)
712 void MEDPresentation::threshold() {
713 _hideDataOutsideCustomRange ? thresholdPresentation() : unThresholdPresentation();
716 void MEDPresentation::thresholdPresentation() {
717 if (!_hideDataOutsideCustomRange)
720 internalGenerateThreshold();
722 // Hide _dispVar, for that temporary switch the _presentationVisibility and _hideDataOutsideCustomRange
723 // flag to false and call visibility() method
724 bool prevVisibility = _presentationVisibility;
725 bool prevHideDataOutsideCustomRange = _hideDataOutsideCustomRange;
726 _presentationVisibility = false;
727 _hideDataOutsideCustomRange = false;
729 _presentationVisibility = prevVisibility;
730 _hideDataOutsideCustomRange = prevHideDataOutsideCustomRange;
732 // Display _thresholdDispVar var
735 // Select target colormap
738 // Adapt scalar bar title
741 // Additional threshold actions to be done
742 additionalThresholdActions();
744 _presentationThresolds[getThresholdIndex()]._active = true;
747 void MEDPresentation::thresholdValues() {
748 if (!_hideDataOutsideCustomRange)
750 std::ostringstream oss;
751 oss << _presentationThresolds[getThresholdIndex()]._thresholdVar << ".ThresholdRange = [ " << _scalarBarRangeArray[0] << ", " << _scalarBarRangeArray[1] << "];";
752 oss << _presentationThresolds[getThresholdIndex()]._thresholdLutVar <<".RescaleTransferFunction(" << _scalarBarRangeArray[0] << ", " << _scalarBarRangeArray[1] << ");";
753 pushAndExecPyLine(oss.str());
756 void MEDPresentation::unThresholdPresentation() {
758 if (_presentationThresolds[getThresholdIndex()]._active) {
759 // Hide _dispVar, for that temporary switch the _presentationVisibility to talse and _hideDataOutsideCustomRange
760 // flag to true and call visibility() method
761 bool prevVisibility = _presentationVisibility;
762 bool prevHideDataOutsideCustomRange = _hideDataOutsideCustomRange;
763 _presentationVisibility = false;
764 _hideDataOutsideCustomRange = true;
766 _presentationVisibility = prevVisibility;
767 _hideDataOutsideCustomRange = prevHideDataOutsideCustomRange;
770 rescaleTransferFunction();
772 // Display _dispVar var
775 // Select target colormap
778 // Adapt scalar bar title
781 // Additional unthreshold actions to be done
782 additionalUnThresholdActions();
784 _presentationThresolds[getThresholdIndex()]._active = false;
788 int MEDPresentation::getThresholdIndex() const {
789 if (_nbComponentsInThresholdInput > 1 && _nbComponentsInThresholdInput <= 3) {
790 return _selectedComponentIndex + 1;
793 return _selectedComponentIndex;
798 Return _dispVar or _thresholdDispVar depending on _hideDataOutsideCustomRange flag:
799 _hideDataOutsideCustomRange == false : _dispVar is used
800 _hideDataOutsideCustomRange == true : _thresholdDispVar is used
802 const std::string& MEDPresentation::getDispVar() {
803 return (_hideDataOutsideCustomRange ? _presentationThresolds[getThresholdIndex()]._thresholdDispVar : _dispVar);
807 Return _dispVar or _thresholdDispVar depending on _hideDataOutsideCustomRange flag:
808 _hideDataOutsideCustomRange == false : _dispVar is used
809 _hideDataOutsideCustomRange == true : _thresholdDispVar is used
811 const std::string& MEDPresentation::getLutVar() {
812 return (_hideDataOutsideCustomRange ? _presentationThresolds[getThresholdIndex()]._thresholdLutVar : _lutVar);
816 MEDPresentation::rescaleTransferFunction()
818 if (_hideDataOutsideCustomRange)
821 std::ostringstream oss;
824 case MEDCALC::SCALAR_BAR_ALL_TIMESTEPS:
825 oss << _dispVar << ".RescaleTransferFunctionToDataRangeOverTime();";
827 case MEDCALC::SCALAR_BAR_CURRENT_TIMESTEP:
828 oss << _dispVar << ".RescaleTransferFunctionToDataRange(False);";
830 case MEDCALC::SCALAR_BAR_CUSTOM_RANGE:
831 oss << _lutVar << ".RescaleTransferFunction("<< _scalarBarRangeArray[0]<<", "<< _scalarBarRangeArray[1]<<");";
834 STDLOG("MEDPresentation::getRescaleCommand(): invalid range!");
835 throw KERNEL::createSalomeException("MEDPresentation::getRescaleCommand(): invalid range!");
837 pushAndExecPyLine(oss.str()); oss.str("");
839 oss << _rangeVar << " = [" << _lutVar << ".RGBPoints[0], " << _lutVar << ".RGBPoints[-4]];";
840 execPyLine(oss.str());
842 //Update _scalarBarRange internal variable in case of rescaling to "Data Range" or "Data Range Over All Times"
843 if (_sbRange == MEDCALC::SCALAR_BAR_ALL_TIMESTEPS ||
844 _sbRange == MEDCALC::SCALAR_BAR_CURRENT_TIMESTEP) {
845 MEDPyLockWrapper lock;
846 PyObject * obj = getPythonObjectFromMain(_rangeVar.c_str());
847 if (obj && PyList_Check(obj)) {
848 PyObject* objL0 = PyList_GetItem(obj, 0);
849 PyObject* objL1 = PyList_GetItem(obj, 1);
850 if (PyFloat_Check(objL0)) {
851 double min = PyFloat_AsDouble(objL0);
852 _scalarBarRangeArray[0] = min;
854 if (PyFloat_Check(objL1)) {
855 double max = PyFloat_AsDouble(objL1);
856 _scalarBarRangeArray[1] = max;
859 setDoubleProperty(MEDPresentation::PROP_SCALAR_BAR_MIN_VALUE, _scalarBarRangeArray[0]);
860 setDoubleProperty(MEDPresentation::PROP_SCALAR_BAR_MAX_VALUE, _scalarBarRangeArray[1]);
862 // Adapt scalar bar title
866 MEDCALC::PresentationVisibility
867 MEDPresentation::presentationStateInActiveView() {
868 MEDPyLockWrapper lock;
869 MEDCALC::PresentationVisibility result = MEDCALC::PRESENTATION_NOT_IN_VIEW;
871 execPyLine("__isInView = ( " + getRenderViewVar() + " == pvs.GetActiveView() )");
872 PyObject * obj = getPythonObjectFromMain("__isInView");
874 if (obj && PyBool_Check(obj) && (obj == Py_True)) {
875 result = _presentationVisibility ? MEDCALC::PRESENTATION_VISIBLE : MEDCALC::PRESENTATION_INVISIBLE;
881 MEDPresentation::GeneratePythonId()
883 static int INIT_ID = 0;
887 bool MEDPresentation::isThresoldActive() const {
889 for (auto const& value : _presentationThresolds) {
890 active = active || value._active;
896 MEDPresentation::activateView()
898 MEDPyLockWrapper lock;
900 execPyLine("__alive = " + getRenderViewVar() + " in pvs.GetRenderViews()");
901 PyObject * obj = getPythonObjectFromMain("__alive");
903 if (obj && PyBool_Check(obj))
904 alive = (obj == Py_True);
907 // The view is still there,just activate it:
908 pushAndExecPyLine("pvs.SetActiveView(" + getRenderViewVar() + ");");
911 // The view disappeared, recreate it in a new layout. The transfer of the objects is to be done by the caller.
912 std::ostringstream oss;
913 oss << "pvs.servermanager.misc.ViewLayout(registrationGroup='layouts');";
914 pushAndExecPyLine(oss.str()); oss.str("");
915 oss << getRenderViewVar() << " = pvs.CreateView('RenderView');";
916 pushAndExecPyLine(oss.str()); oss.str("");
922 * Called when the view has been recreated (because the user closed it).
923 * All the objects and set up are re-shown in the new view (which is stored in the same Python variable).
926 MEDPresentation::recreateViewSetup()
928 bool prevHideDataOutsideCustomRange = _hideDataOutsideCustomRange;
929 _hideDataOutsideCustomRange = false;
934 rescaleTransferFunction();
935 _hideDataOutsideCustomRange = prevHideDataOutsideCustomRange;
937 resetCameraAndRender();
941 MEDPresentation::paravisDump() const
945 for (vector<string>::const_iterator it=_pythonCmds.begin(); it != _pythonCmds.end(); ++it)
954 * Query all available component names for the field associated with this presentation.
955 * Fills in all the corresponding string properties:
959 * and the number of components.
962 MEDPresentation::fillAvailableFieldComponents()
964 MEDPyLockWrapper lock; // GIL!
965 std::string typ = getScriptCellType();
967 std::ostringstream oss;
968 oss << "__nbCompo = " << _srcObjVar << "." << typ << ".GetArray('" << _fieldName << "').GetNumberOfComponents();";
969 execPyLine(oss.str());
970 PyObject* p_obj = getPythonObjectFromMain("__nbCompo");
972 if (p_obj && PyLong_Check(p_obj))
973 nbCompo = PyLong_AS_LONG(p_obj);
976 STDLOG("Unexpected Python error");
977 throw KERNEL::createSalomeException("Unexpected Python error");
979 _nbComponents = nbCompo;
980 _nbComponentsInThresholdInput = _nbComponents;
981 setIntProperty(MEDPresentation::PROP_NB_COMPONENTS, nbCompo);
983 // if the field is not a vector (2 or 3 components), select the first component of the tensor,
984 // like in WidgetPresentationParameters::setComponents
985 if (!(nbCompo > 1 && nbCompo <= 3))
986 _selectedComponentIndex = 0;
988 std::map<std::string, long> aCompoMap;
989 std::vector <std::string> aCompos;
990 for (long i = 0; i<nbCompo; i++)
992 std::ostringstream oss2;
993 oss2 << "__compo = " << _srcObjVar << "." << typ << ".GetArray('" << _fieldName << "').GetComponentName(" << i << ");";
994 execPyLine(oss2.str());
995 PyObject* p_obj = getPythonObjectFromMain("__compo");
997 if (p_obj && PyUnicode_Check(p_obj))
998 compo = std::string(Py_EncodeLocale(PyUnicode_AS_UNICODE(p_obj), NULL)); // pointing to internal Python memory, so make a copy!!
1001 STDLOG("Unexpected Python error");
1002 throw KERNEL::createSalomeException("Unexpected Python error");
1004 if (aCompoMap.find(compo) == aCompoMap.end()) {
1005 aCompoMap.insert(std::pair<std::string, int>(compo, 1));
1006 aCompos.push_back(compo);
1009 if (aCompoMap[compo] == 1) {
1010 for (std::vector<std::string>::size_type ii = 0; ii != aCompos.size(); ii++) {
1011 // Modify the previous occurrence
1012 if (aCompos[ii] == compo) {
1013 std::ostringstream oss_m;
1014 oss_m << compo << "(" << 1 << ")";
1015 aCompos[ii] = oss_m.str();
1019 std::ostringstream oss_n;
1020 oss_n << compo << "(" << 2 << ")";
1021 aCompos.push_back(oss_n.str());
1023 else if (aCompoMap[compo] > 1) {
1024 auto val = aCompoMap[compo];
1026 std::ostringstream oss_n;
1027 oss_n << compo << "(" << val << ")";
1028 aCompos.push_back(oss_n.str());
1030 aCompoMap[compo] = aCompoMap[compo] + 1;
1033 std::string aCopy = _programmableVar;
1034 std::string id = aCopy.replace(aCopy.find(PROGRAMMABLE), std::string(aCopy).length() - 1, "");
1036 std::vector<std::string>::size_type up = (nbCompo > 1) ? nbCompo + 1 : nbCompo;
1037 for (std::vector<std::string>::size_type i = 0; i != up; i++) {
1038 std::ostringstream oss_p;
1039 if (i != 0 || nbCompo == 1) {
1040 std::vector<std::string>::size_type idx = (nbCompo > 1) ? i - 1 : i;
1041 oss_p << MEDPresentation::PROP_COMPONENT << idx;
1042 setStringProperty(oss_p.str(), aCompos[idx]);
1044 std::ostringstream oss_thd, oss_th, oss_thl;
1045 oss_th << "__threshold" << id <<"_"<<i;
1046 oss_thd << "__thresholdDisp" << id << "_" << i;
1047 oss_thl << "__thresholdLut" << id << "_" << i;
1048 ComponentThresold ct = ComponentThresold();
1049 ct._thresholdVar = oss_th.str();
1050 ct._thresholdDispVar = oss_thd.str();
1051 ct._thresholdLutVar = oss_thl.str();
1052 _presentationThresolds.push_back(ct);
1056 std::string MEDPresentation::getThresholdFieldName() const {
1057 std::string result = getFieldName();
1058 if (_nbComponentsInThresholdInput > 1 && _hideDataOutsideCustomRange) {
1059 std::ostringstream oss;
1060 if (_selectedComponentIndex == -1) {
1061 oss << _fieldName << "_magnitude";
1064 oss << _fieldName << "_" << _selectedComponentIndex + 1;
1071 std::string MEDPresentation::getFieldName() const {
1075 std::string MEDPresentation::toScriptCellType(const std::string& pvType) {
1076 std::string typ = "";
1077 if (pvType == "CELLS") {
1080 else if (pvType == "POINTS") {
1084 std::string msg("Unsupported spatial discretisation: " + pvType);
1086 throw KERNEL::createSalomeException(msg.c_str());
1091 std::string MEDPresentation::getScriptCellType() const {
1092 return toScriptCellType(_pvFieldType);
1096 * In case where a CELLS field needs to be converted to POINT field.
1097 * This updates the source object to become the result of the CellDatatoPointData filter.
1100 MEDPresentation::applyCellToPointIfNeeded()
1102 if (_pvFieldType == "CELLS")
1104 std::ostringstream oss, oss2;
1105 // Apply Cell data to point data:
1106 oss2 << "__srcObj" << GeneratePythonId();
1107 oss << oss2.str() << " = pvs.CellDatatoPointData(Input=" << _srcObjVar << ");";
1108 pushAndExecPyLine(oss.str()); oss.str("");
1109 // Now the source becomes the result of the CellDatatoPointData:
1110 _srcObjVar = oss2.str();
1115 * Delete threshold filters and programmable filter
1118 MEDPresentation::deleteThresholds() {
1119 std::ostringstream oss;
1120 for (auto& value : _presentationThresolds) {
1121 if (value._active) {
1122 oss << "pvs.Hide(" << value._thresholdVar << ");";
1124 if (value._thresholdInitialized) {
1125 oss << "pvs.Delete(" << value._thresholdVar <<");";
1129 if (_programmableInitialized) {
1130 oss << "pvs.Delete(" << _programmableVar << ");";
1131 _programmableInitialized = false;
1133 pushAndExecPyLine(oss.str());
1137 // * Convert a vector field into a 3D vector field:
1138 // * - if the vector field is already 3D, nothing to do
1139 // * - if it is 2D, then add a null component
1140 // * - otherwise (tensor field, scalar field) throw
1143 //MEDPresentation::convertTo3DVectorField()
1145 // std::ostringstream oss, oss1, oss2, oss3;
1147 // int nbCompo = getIntProperty(MEDPresentation::PROP_NB_COMPONENTS);
1148 // if (nbCompo < 2 || nbCompo > 3)
1150 // oss << "The field '" << _fieldName << "' must have 2 or 3 components for this presentation!";
1151 // STDLOG(oss.str());
1152 // throw KERNEL::createSalomeException(oss.str().c_str());
1154 // if (nbCompo == 3)
1157 // // Apply calculator:
1158 // oss2 << "__srcObj" << GeneratePythonId();
1159 // oss << oss2.str() << " = pvs.Calculator(Input=" << _srcObjVar << ");";
1160 // pushAndExecPyLine(oss.str()); oss.str("");
1161 // // Now the source becomes the result of the CellDatatoPointData:
1162 // _srcObjVar = oss2.str();
1164 // if(_pvFieldType == "CELLS")
1165 // typ = "Cell Data";
1166 // else if(_pvFieldType == "POINTS")
1167 // typ = "Point Data";
1170 // oss3 << "Field '" << _fieldName << "' has invalid field type";
1171 // STDLOG(oss3.str());
1172 // throw KERNEL::createSalomeException(oss3.str().c_str());
1174 // oss << _srcObjVar << ".AttributeMode = '" << typ << "';";
1175 // pushAndExecPyLine(oss.str()); oss.str("");
1176 // oss << _srcObjVar << ".ResultArrayName = '" << _fieldName << "_CALC';"; // will never be needed I think
1177 // pushAndExecPyLine(oss.str()); oss.str("");
1178 // oss << _srcObjVar << ".Function = '" << _fieldName << "_0*iHat + " << _fieldName << "_1*jHat + 0.0*zHat';";
1179 // pushAndExecPyLine(oss.str()); oss.str("");