1 // Copyright (C) 2011-2024 CEA, EDF
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);
40 const std::string MEDPresentation::PROP_NAME = "name";
41 const std::string MEDPresentation::PROP_NB_COMPONENTS = "nbComponents";
42 const std::string MEDPresentation::PROP_SELECTED_COMPONENT = "selectedComponent";
43 const std::string MEDPresentation::PROP_COMPONENT = "component_";
44 const std::string MEDPresentation::PROP_COLOR_MAP = "colorMap";
45 const std::string MEDPresentation::PROP_SCALAR_BAR_RANGE = "scalarBarRange";
46 const std::string MEDPresentation::PROP_VISIBILITY = "visibility";
47 const std::string MEDPresentation::PROP_SCALAR_BAR_VISIBILITY = "scalarBarVisibility";
48 const std::string MEDPresentation::PROP_SCALAR_BAR_MIN_VALUE = "scalarBarMinValue";
49 const std::string MEDPresentation::PROP_SCALAR_BAR_MAX_VALUE = "scalarBarMaxValue";
50 const std::string MEDPresentation::PROP_HIDE_DATA_OUTSIDE_CUSTOM_RANGE = "hideDataOutsideCustomRange";
52 #define PROGRAMMABLE "__programmable"
54 MEDPresentation::MEDPresentation(MEDPresentation::TypeID handlerId, const std::string& name,
55 const MEDCALC::ViewModeType viewMode,
56 const MEDCALC::ColorMapType colorMap,
57 const MEDCALC::ScalarBarRangeType sbRange)
58 : _meshName(""), _fileName(""), _fieldName(""),
59 _mcFieldType(MEDCoupling::ON_CELLS),
61 _handlerId(handlerId),
62 _selectedComponentIndex(-1),
66 _renderViewPyId(-1), // will be set by MEDPresentationManager_i::_makePresentation()
68 _presentationVisibility(true),
69 _scalarBarVisibility(true),
70 _scalarBarRangeArray{ 0.0, 100.0 },
71 _programmableInitialized(false),
72 _hideDataOutsideCustomRange(false),
74 _nbComponentsInThresholdInput(0)
76 setStringProperty(MEDPresentation::PROP_NAME, name);
78 setIntProperty(MEDPresentation::PROP_NB_COMPONENTS, 0);
79 setIntProperty(MEDPresentation::PROP_SELECTED_COMPONENT, 0);
81 setIntProperty(MEDPresentation::PROP_COLOR_MAP, static_cast<int>(colorMap));
82 setIntProperty(MEDPresentation::PROP_SCALAR_BAR_RANGE, static_cast<int>(sbRange));
83 setIntProperty(MEDPresentation::PROP_VISIBILITY, static_cast<int>(_presentationVisibility));
84 setIntProperty(MEDPresentation::PROP_SCALAR_BAR_VISIBILITY, static_cast<int>(_scalarBarVisibility));
85 setDoubleProperty(MEDPresentation::PROP_SCALAR_BAR_MIN_VALUE, _scalarBarRangeArray[0]);
86 setDoubleProperty(MEDPresentation::PROP_SCALAR_BAR_MAX_VALUE, _scalarBarRangeArray[1]);
87 setIntProperty(MEDPresentation::PROP_HIDE_DATA_OUTSIDE_CUSTOM_RANGE, static_cast<int>(_hideDataOutsideCustomRange));
91 int id = GeneratePythonId();
92 std::ostringstream oss_o, oss_d, oss_l, oss_s, oss_r, oss_cl, oss_p;
93 oss_o << "__obj" << id;
94 oss_s << "__srcObj" << id;
95 oss_d << "__disp" << id;
96 oss_l << "__lut" << id;
97 oss_r << "__range" << id;
98 oss_p << PROGRAMMABLE << id;
99 _objVar = oss_o.str();
100 _srcObjVar = oss_s.str();
101 _dispVar = oss_d.str();
102 _lutVar = oss_l.str();
103 _rangeVar = oss_r.str();
104 _programmableVar = oss_p.str();
108 * For most of the presentations the field name etc is required.
109 * For the MEDPresentationMeshView however, the handler ID is a mesh handler ID, not a field, and the
110 * treatment is specific.
113 MEDPresentation::initFieldMeshInfos()
115 MEDCALC::MEDDataManager_ptr dataManager(MEDFactoryClient::getDataManager());
116 MEDCALC::FieldHandler* fieldHandler = dataManager->getFieldHandler(_handlerId);
117 MEDCALC::MeshHandler* meshHandler = dataManager->getMeshHandler(fieldHandler->meshid);
118 //MEDCALC::DatasourceHandler* dataSHandler = dataManager->getDatasourceHandlerFromID(meshHandler->sourceid); // todo: unused
120 // get the file name of the field (or its memory information)
121 extractFileName(std::string(fieldHandler->source));
123 _fieldName = fieldHandler->fieldname;
124 _mcFieldType = (MEDCoupling::TypeOfField) fieldHandler->type;
125 _pvFieldType = getPVFieldTypeString(_mcFieldType);
126 _colorByType = _pvFieldType; // by default the same; overridden in DeflectionShape, VectorField, PointSprite and Contour, Plot3D
127 _meshName = meshHandler->name;
131 MEDPresentation::extractFileName(const std::string& name)
133 STDLOG("MEDPresentation::extractFileName('" << name << "')");
135 if (_fileName.substr(0, 7) != std::string("file://")) {
136 STDLOG("MEDPresentation(): Data source is in memory! Saving it in tmp file.");
137 // export a med file with this field
138 // we could instead use CORBA to transfer the field to PARAVIS like in MEDCalculatorDBFieldReal::display()
139 _fileName = std::tmpnam(NULL);
140 MEDCALC::FieldIdList fieldIdList;
141 fieldIdList.length(1);
142 fieldIdList[0] = _handlerId;
143 MEDFactoryClient::getDataManager()->saveFields(_fileName.c_str(), fieldIdList);
146 // removing "file://"
147 _fileName = _fileName.substr(7, _fileName.size());
148 STDLOG("MEDPresentation::extractFileName _fileName=" << _fileName);
151 MEDPresentation::~MEDPresentation()
153 STDLOG("~MEDPresentation(): clear display");
155 MEDPyLockWrapper lock;
156 std::ostringstream oss;
159 oss << "pvs.Hide(" << _objVar << ", view=" << getRenderViewVar() << ");";
160 for (auto& value : _presentationThresolds) {
162 oss << "pvs.Hide(" << value._thresholdVar << ", view=" << getRenderViewVar() << ");";
165 execPyLine(oss.str());
166 // :TRICKY: The two following lines raise an exception when closing MED module
167 // after sequence: MED - load file - PARAVIS - MED - close SALOME
168 // (see Mantis #23461)
169 //execPyLine(getRenderViewVar() + ".ResetCamera();");
170 //execPyLine("pvs.Render();");
172 catch(SALOME::SALOME_Exception&) {
178 MEDPresentation::generatePipeline()
180 // Might be more complicated in the future:
182 this->internalGeneratePipeline();
185 void MEDPresentation::internalGenerateThreshold() {
186 std::ostringstream oss;
187 std::string inputFieldName = getFieldName();
188 if (!_programmableInitialized) {
189 if (_nbComponentsInThresholdInput > 1) {
190 std::string typ = toScriptCellType(_colorByType);
191 oss << _programmableVar << " = pvs.ProgrammableFilter(Input = " << _objVar << ");";
192 oss << _programmableVar << ".Script = \"\"\"import numpy as np" << std::endl;
193 oss << "import paraview.vtk.numpy_interface.dataset_adapter as dsa" << std::endl;
194 oss << "input0 = inputs[0]" << std::endl;
195 oss << "inputDataArray=input0." << typ << "['" << inputFieldName << "']" << std::endl;
196 oss << "if type(inputDataArray) == dsa.VTKCompositeDataArray:" << std::endl;
197 oss << "\tnpa = inputDataArray.GetArrays()" << std::endl;
198 oss << "else:" << std::endl;
199 oss << "\tnpa = inputDataArray" << std::endl;
200 oss << "if type(npa) == list:" << std::endl;
201 oss << "\tarrs = []" << std::endl;
202 oss << "\tfor a in npa:" << std::endl;
203 oss << "\t\tmgm = np.linalg.norm(a, axis = -1)" << std::endl;
204 oss << "\t\tmga = mgm.reshape(mgm.size, 1)" << std::endl;
205 oss << "\t\tarrs.append(mga)" << std::endl;
206 oss << "\tca = dsa.VTKCompositeDataArray(arrs)" << std::endl;
207 oss << "\toutput." << typ << ".append(ca, '" << inputFieldName << "_magnitude')" << std::endl;
208 oss << "else:" << std::endl;
209 oss << "\tmgm = np.linalg.norm(npa, axis = -1)" << std::endl;
210 oss << "\tmga = mgm.reshape(mgm.size, 1)" << std::endl;
211 oss << "\toutput." << typ << ".append(mga, '" << inputFieldName << "_magnitude')" << std::endl;
212 for (std::vector<std::string>::size_type ii = 1; ii < _nbComponentsInThresholdInput + 1 ; ii++) {
213 oss << "dataArray" << ii << " = inputDataArray[:, [" << ii - 1 << "]]" << std::endl;
214 oss << "output." << typ << ".append(dataArray" << ii << ", '" << inputFieldName << "_" << ii << "')" << std::endl;
216 oss << "\"\"\"" << std::endl;
217 _programmableInitialized = true;
221 ComponentThresold& currentThreshold = _presentationThresolds[getThresholdIndex()];
222 if (!currentThreshold._thresholdInitialized) {
223 std::string& thInput = (_nbComponentsInThresholdInput > 1 ) ? _programmableVar : _objVar;
224 std::string arrayName = getThresholdFieldName();
225 oss << currentThreshold._thresholdVar << " = pvs.Threshold(Input = " << thInput << ");";
226 oss << currentThreshold._thresholdVar << ".Scalars = ['" << _colorByType << "', '" << arrayName << "'];";
227 oss << additionalThresholdInitializationActions();
228 oss << currentThreshold._thresholdDispVar << " = pvs.Show(" << currentThreshold._thresholdVar << ", "
229 << getRenderViewVar() << ");";
230 oss << currentThreshold._thresholdLutVar << " = pvs.GetColorTransferFunction('" << arrayName << "', "
231 << currentThreshold._thresholdDispVar << ", separate=True);";
232 oss << "pvs.ColorBy(" << currentThreshold._thresholdDispVar << ", ('" << _colorByType << "', '"
233 << arrayName << "'), separate = True);";
234 oss << additionalThresholdVisualizationActions();
235 currentThreshold._thresholdInitialized = true;
237 if (oss.str().length() > 0) {
238 pushAndExecPyLine(oss.str());
243 //MEDPresentation::pushPyObjects(PyObjectId obj, PyObjectId disp)
245 // _pipeline.push_back(obj);
246 // _display.push_back(disp);
250 MEDPresentation::pushAndExecPyLine(const std::string & lin)
253 _pythonCmds.push_back(lin);
257 MEDPresentation::execPyLine(const std::string & lin)
259 MEDPyLockWrapper lock;
260 STDLOG("@@@@ MEDPresentation::execPyLine() about to exec >> " << lin);
261 if(PyRun_SimpleString(lin.c_str()))
263 std::ostringstream oss;
264 oss << "MEDPresentation::execPyLine(): following Python command failed!\n";
267 throw KERNEL::createSalomeException(oss.str().c_str());
272 MEDPresentation::setStringProperty(const std::string& propName, const std::string& propValue)
274 _propertiesStr[propName] = propValue;
278 MEDPresentation::getStringProperty(const std::string& propName) const
280 std::map<std::string, std::string>::const_iterator it = _propertiesStr.find(propName);
281 if (it != _propertiesStr.end()) {
285 STDLOG("MEDPresentation::getStringProperty(): no property named " + propName);
286 throw MEDPresentationException("MEDPresentation::getStringProperty(): no property named " + propName);
291 MEDPresentation::setIntProperty(const std::string& propName, const int propValue)
293 _propertiesInt[propName] = propValue;
297 MEDPresentation::getIntProperty(const std::string& propName) const
299 std::map<std::string, int>::const_iterator it = _propertiesInt.find(propName);
300 if (it != _propertiesInt.end()) {
304 STDLOG("MEDPresentation::getIntProperty(): no property named " + propName);
305 throw MEDPresentationException("MEDPresentation::getIntProperty(): no property named " + propName);
310 MEDPresentation::dumpIntProperties() const
312 std::map<std::string, int>::const_iterator it = _propertiesInt.begin();
313 STDLOG("@@@ Dumping INT properties");
314 for(; it != _propertiesInt.end(); ++it)
316 std::ostringstream oss;
317 oss << (*it).first << " -> " << (*it).second;
323 MEDPresentation::setDoubleProperty(const std::string& propName, const double propValue)
325 _propertiesDouble[propName] = propValue;
329 MEDPresentation::getDoubleProperty(const std::string& propName) const
331 std::map<std::string, double>::const_iterator it = _propertiesDouble.find(propName);
332 if (it != _propertiesDouble.end()) {
336 STDLOG("MEDPresentation::getDoubleProperty(): no property named " + propName);
337 throw MEDPresentationException("MEDPresentation::getDoubleProperty(): no property named " + propName);
342 MEDPresentation::dumpDoubleProperties() const
344 std::map<std::string, double>::const_iterator it = _propertiesDouble.begin();
345 STDLOG("@@@ Dumping DOUBLE properties");
346 for (; it != _propertiesDouble.end(); ++it)
348 std::ostringstream oss;
349 oss << (*it).first << " -> " << (*it).second;
355 MEDPresentation::dumpStringProperties() const
357 std::map<std::string, std::string>::const_iterator it = _propertiesStr.begin();
358 STDLOG("@@@ Dumping STR properties");
359 for(; it != _propertiesStr.end(); ++it)
361 std::ostringstream oss;
362 oss << (*it).first << " -> " << (*it).second;
368 MEDPresentation::internalGeneratePipeline()
370 MEDPyLockWrapper lock;
371 pushAndExecPyLine( "import pvsimple as pvs;");
372 pushAndExecPyLine( "import medcalc");
377 * @return a borrowed reference. Do not DECRREF!
380 MEDPresentation::getPythonObjectFromMain(const char* python_var) const
384 // All the calls below returns *borrowed* references
385 PyObject* main_module = PyImport_AddModule((char*)"__main__");
386 _globalDict = PyModule_GetDict(main_module);
388 return PyDict_GetItemString(_globalDict, python_var);
392 MEDPresentation::getPVFieldTypeString(MEDCoupling::TypeOfField fieldType) const
396 case MEDCoupling::ON_CELLS:
398 case MEDCoupling::ON_NODES:
400 case MEDCoupling::ON_GAUSS_PT:
401 return "POINTS"; // because internally after application of the ELGA filter, the field will appear as a POINT field
402 case MEDCoupling::ON_GAUSS_NE:
403 return "POINTS"; // because internally after application of the ELNO mesh filter, the field will appear as a POINT field
405 STDLOG("MEDPresentation::getPVFieldTypeString() -- Not implemented ! ELNO field?");
411 MEDPresentation::getRenderViewVar() const
413 std::ostringstream oss;
414 oss << "__view" << _renderViewPyId;
419 * Creates the MEDReader source in the pipeline, and potentially apply GAUSS/ELNO filters.
422 MEDPresentation::createSource()
425 switch(_mcFieldType) {
426 case MEDCoupling::ON_CELLS: typ = "P0"; break;
427 case MEDCoupling::ON_NODES: typ = "P1"; break;
428 case MEDCoupling::ON_GAUSS_PT: typ = "GAUSS"; break;
429 case MEDCoupling::ON_GAUSS_NE: typ = "GSSNE"; break;
431 const char * msg ="MEDPresentation::createSource(): field type not impl. yet!";
433 throw KERNEL::createSalomeException(msg);
436 std::ostringstream oss;
437 oss << _srcObjVar << " = pvs.MEDReader(FileNames=r'" << _fileName << "');";
438 pushAndExecPyLine(oss.str()); oss.str("");
439 oss << "medcalc.SelectSourceField(" << _srcObjVar << ", '" << _meshName << "', '"
440 << _fieldName << "', '" << typ << "');";
441 pushAndExecPyLine(oss.str()); oss.str("");
442 // Generate complete vector fields: fields with 2 components will copied into <name>_vector and
443 // have a third null component added.
444 oss << _srcObjVar << ".VectorsProperty = 1;";
445 pushAndExecPyLine(oss.str()); oss.str("");
447 // Make sure this is set so we stick to time steps:
448 pushAndExecPyLine("pvs.GetAnimationScene().PlayMode = 'Snap To TimeSteps'");
450 // Deal with GAUSS fields:
451 if(_mcFieldType == MEDCoupling::ON_GAUSS_PT)
453 std::ostringstream oss, oss2;
454 oss2 << "__srcObj" << GeneratePythonId();
455 oss << oss2.str() << " = pvs.ELGAfieldToPointGaussian(Input=" << _srcObjVar << ");";
456 pushAndExecPyLine(oss.str()); oss.str("");
457 // Now the source becomes the result of the CellDatatoPointData:
458 _srcObjVar = oss2.str();
459 oss << _srcObjVar << ".SelectSourceArray = ['CELLS', 'ELGA@0'];";
460 pushAndExecPyLine(oss.str()); oss.str("");
462 if(_mcFieldType == MEDCoupling::ON_GAUSS_NE)
464 std::ostringstream oss, oss2;
465 oss2 << "__srcObj" << GeneratePythonId();
466 oss << oss2.str() << " = pvs.ELNOfieldToSurface(Input=" << _srcObjVar << ");";
467 pushAndExecPyLine(oss.str()); oss.str("");
468 // Now the source becomes the result of the CellDatatoPointData:
469 _srcObjVar = oss2.str();
474 * Set the timestamp of the animation to the timestamp of the field.
475 * Especially useful when working on a field's iteration:
476 * in the workspace, in the python console, or using changeUnderlyingMesh.
479 MEDPresentation::setTimestamp()
481 // get the timestamp of the field
482 double timestamp = MEDFactoryClient::getDataManager()->getFieldTimestamp(_handlerId);
483 STDLOG("Displaying timestamp : " << timestamp);
485 std::ostringstream oss;
487 // go to the right timestamp in animation (view and VCR toolbar)
488 pushAndExecPyLine("pvs.GetAnimationScene().UpdateAnimationUsingDataTimeSteps()");
489 oss << "pvs.GetAnimationScene().AnimationTime = " << timestamp << ";";
490 pushAndExecPyLine(oss.str()); oss.str("");
491 oss << "pvs.GetTimeKeeper().Time = " << timestamp << ";";
492 pushAndExecPyLine(oss.str()); oss.str("");
496 MEDPresentation::setOrCreateRenderView()
498 std::ostringstream oss2;
500 std::string view(getRenderViewVar());
501 oss2 << "pvs._DisableFirstRenderCameraReset();";
502 pushAndExecPyLine(oss2.str()); oss2.str("");
503 if (_viewMode == MEDCALC::VIEW_MODE_OVERLAP) {
504 // this might potentially re-assign to an existing view variable, but this is OK, we
505 // normally reassign exactly the same RenderView object.
506 oss2 << view << " = medcalc.FindOrCreateView('RenderView');";
507 pushAndExecPyLine(oss2.str()); oss2.str("");
508 } else if (_viewMode == MEDCALC::VIEW_MODE_REPLACE) {
510 oss2 << view << " = medcalc.FindOrCreateView('RenderView');";
511 pushAndExecPyLine(oss2.str()); oss2.str("");
512 oss2 << "pvs.active_objects.source and pvs.Hide(view=" << view << ");";
513 pushAndExecPyLine(oss2.str()); oss2.str("");
514 oss2 << "pvs.Render();";
515 pushAndExecPyLine(oss2.str()); oss2.str("");
516 } else if (_viewMode == MEDCALC::VIEW_MODE_NEW_LAYOUT) {
517 oss2 << "nbLayouts = len(pvs.GetLayouts());";
518 pushAndExecPyLine(oss2.str()); oss2.str("");
519 oss2 << "__layout1 = pvs.CreateLayout('Layout #%i'%(nbLayouts+1));";
520 pushAndExecPyLine(oss2.str()); oss2.str("");
521 oss2 << view << " = pvs.CreateView('RenderView');";
522 pushAndExecPyLine(oss2.str()); oss2.str("");
523 oss2 << "pvs.AssignViewToLayout(view=" << view << ", layout=__layout1, hint=0);";
524 pushAndExecPyLine(oss2.str()); oss2.str("");
525 } else if (_viewMode == MEDCALC::VIEW_MODE_SPLIT_VIEW) {
526 oss2 << "__activeLayout = pvs.GetLayout();";
527 pushAndExecPyLine(oss2.str()); oss2.str("");
528 oss2 << "__activeLayout.SplitHorizontal(0, 0.5);";
529 pushAndExecPyLine(oss2.str()); oss2.str("");
530 oss2 << view << " = pvs.CreateView('RenderView');";
531 pushAndExecPyLine(oss2.str()); oss2.str("");
532 oss2 << "pvs.AssignViewToLayout(view=" << view << ", layout=__activeLayout, hint=2);";
533 pushAndExecPyLine(oss2.str()); oss2.str("");
538 MEDPresentation::resetCameraAndRender()
540 pushAndExecPyLine(getRenderViewVar() + ".ResetCamera();");
541 pushAndExecPyLine("pvs.Render();");
545 MEDPresentation::selectFieldComponent()
547 std::ostringstream oss, oss_l;
549 if (!_hideDataOutsideCustomRange) {
550 if (_selectedComponentIndex != -1)
552 oss << _lutVar << ".VectorMode = 'Component';";
553 pushAndExecPyLine(oss.str()); oss.str("");
554 oss << _lutVar << ".VectorComponent = " << _selectedComponentIndex << ";";
555 pushAndExecPyLine(oss.str()); oss.str("");
557 else // Euclidean norm
559 oss << _lutVar << ".VectorMode = 'Magnitude';";
560 pushAndExecPyLine(oss.str()); oss.str("");
564 // Make sure that threshold is initialized
565 internalGenerateThreshold();
570 selectColorMap(false);
572 if (!_presentationThresolds[getThresholdIndex()]._active) {
573 std::vector<std::string>::size_type idx = (_nbComponentsInThresholdInput > 1) ? -1 : 0;
574 for (auto& value : _presentationThresolds) {
575 // Hide previous threshold
577 bool currentVisibility = _presentationVisibility;
578 std::vector<std::string>::size_type currentIndex = _selectedComponentIndex;
579 _presentationVisibility = false;
580 _selectedComponentIndex = idx;
582 _selectedComponentIndex = currentIndex;
583 _presentationVisibility = currentVisibility;
584 value._active = false;
588 // Show new threshold
590 _presentationThresolds[getThresholdIndex()]._active = true;
597 * Needs the LUT, so to be called after selectColorMap for the first time.
600 MEDPresentation::scalarBarTitle()
602 // get selected component name:
603 std::string compoName;
604 if (_selectedComponentIndex != -1)
606 std::ostringstream oss1;
607 oss1 << MEDPresentation::PROP_COMPONENT << _selectedComponentIndex;
608 compoName = getStringProperty(oss1.str());
612 if (getIntProperty(MEDPresentation::PROP_NB_COMPONENTS) == 1)
615 compoName = "Magnitude";
617 std::ostringstream oss;
618 if (_hideDataOutsideCustomRange) {
619 oss << "pvs.GetScalarBar(" << getLutVar() << ").Title = '" << _fieldName << "';";
621 oss << "pvs.GetScalarBar(" << getLutVar() << ").ComponentTitle = '" << compoName << "';";
622 pushAndExecPyLine(oss.str()); oss.str("");
626 MEDPresentation::selectColorMap(const bool updateFieldComponent)
628 std::ostringstream oss;
631 case MEDCALC::COLOR_MAP_BLUE_TO_RED_RAINBOW:
632 oss << getLutVar() << ".ApplyPreset('Blue to Red Rainbow',True);";
634 case MEDCALC::COLOR_MAP_COOL_TO_WARM:
635 oss << getLutVar() << ".ApplyPreset('Cool to Warm',True);";
638 STDLOG("MEDPresentation::getColorMapCommand(): invalid colormap!");
639 throw KERNEL::createSalomeException("MEDPresentation::getColorMapCommand(): invalid colormap!");
641 pushAndExecPyLine(oss.str());
643 if(updateFieldComponent) {
644 selectFieldComponent(); // somehow PV keeps the LUT parameters of the previous presentation, so better reset this.
649 MEDPresentation::showObject()
651 std::ostringstream oss;
652 oss << _dispVar << " = pvs.Show(" << _objVar << ", " << getRenderViewVar() << ");";
653 oss << _lutVar << " = pvs.GetColorTransferFunction('" << getFieldName() << "', " << _dispVar << ", separate=True);";
654 pushAndExecPyLine(oss.str());
658 MEDPresentation::hideObject()
660 std::ostringstream oss;
661 oss <<"pvs.Hide(" << _objVar << ", " << getRenderViewVar() << ");";
662 pushAndExecPyLine(oss.str());
666 MEDPresentation::showScalarBar()
668 // Display Scalar Bar only if presentation is visible
669 if (_presentationVisibility) {
670 std::ostringstream oss;
671 oss << getDispVar() << ".SetScalarBarVisibility(" << getRenderViewVar() << ", True);";
672 pushAndExecPyLine(oss.str());
677 MEDPresentation::hideScalarBar()
679 std::ostringstream oss;
680 oss << getDispVar() << ".SetScalarBarVisibility(" << getRenderViewVar() << ", False);";
681 pushAndExecPyLine(oss.str());
685 MEDPresentation::scalarBarVisibility() {
686 _scalarBarVisibility ? showScalarBar() : hideScalarBar();
690 MEDPresentation::colorBy()
692 std::ostringstream oss;
693 oss << "pvs.ColorBy(" << getDispVar() << ", ('" << _colorByType << "', '" << getFieldName() << "'), separate=True);";
694 pushAndExecPyLine(oss.str());
697 void MEDPresentation::visibility() {
698 std::ostringstream oss;
699 oss << getDispVar() << ".Visibility = " << (_presentationVisibility ? "True" : "False") << ";";
700 pushAndExecPyLine(oss.str());
702 // Hide scalar bar with the presentation
703 if (!_presentationVisibility && _scalarBarVisibility)
706 // Show scalar bar with the presentation
707 if (_presentationVisibility && _scalarBarVisibility)
711 void MEDPresentation::threshold() {
712 _hideDataOutsideCustomRange ? thresholdPresentation() : unThresholdPresentation();
715 void MEDPresentation::thresholdPresentation() {
716 if (!_hideDataOutsideCustomRange)
719 internalGenerateThreshold();
721 // Hide _dispVar, for that temporary switch the _presentationVisibility and _hideDataOutsideCustomRange
722 // flag to false and call visibility() method
723 bool prevVisibility = _presentationVisibility;
724 bool prevHideDataOutsideCustomRange = _hideDataOutsideCustomRange;
725 _presentationVisibility = false;
726 _hideDataOutsideCustomRange = false;
728 _presentationVisibility = prevVisibility;
729 _hideDataOutsideCustomRange = prevHideDataOutsideCustomRange;
731 // Display _thresholdDispVar var
734 // Select target colormap
737 // Adapt scalar bar title
740 // Additional threshold actions to be done
741 additionalThresholdActions();
743 _presentationThresolds[getThresholdIndex()]._active = true;
746 void MEDPresentation::thresholdValues() {
747 if (!_hideDataOutsideCustomRange)
749 std::ostringstream oss;
750 oss << _presentationThresolds[getThresholdIndex()]._thresholdVar << ".ThresholdRange = [ " << _scalarBarRangeArray[0] << ", " << _scalarBarRangeArray[1] << "];";
751 oss << _presentationThresolds[getThresholdIndex()]._thresholdLutVar <<".RescaleTransferFunction(" << _scalarBarRangeArray[0] << ", " << _scalarBarRangeArray[1] << ");";
752 pushAndExecPyLine(oss.str());
755 void MEDPresentation::unThresholdPresentation() {
757 if (_presentationThresolds[getThresholdIndex()]._active) {
758 // Hide _dispVar, for that temporary switch the _presentationVisibility to talse and _hideDataOutsideCustomRange
759 // flag to true and call visibility() method
760 bool prevVisibility = _presentationVisibility;
761 bool prevHideDataOutsideCustomRange = _hideDataOutsideCustomRange;
762 _presentationVisibility = false;
763 _hideDataOutsideCustomRange = true;
765 _presentationVisibility = prevVisibility;
766 _hideDataOutsideCustomRange = prevHideDataOutsideCustomRange;
769 rescaleTransferFunction();
771 // Display _dispVar var
774 // Select target colormap
777 // Adapt scalar bar title
780 // Additional unthreshold actions to be done
781 additionalUnThresholdActions();
783 _presentationThresolds[getThresholdIndex()]._active = false;
787 int MEDPresentation::getThresholdIndex() const {
788 if (_nbComponentsInThresholdInput > 1 && _nbComponentsInThresholdInput <= 3) {
789 return _selectedComponentIndex + 1;
792 return _selectedComponentIndex;
797 Return _dispVar or _thresholdDispVar depending on _hideDataOutsideCustomRange flag:
798 _hideDataOutsideCustomRange == false : _dispVar is used
799 _hideDataOutsideCustomRange == true : _thresholdDispVar is used
801 const std::string& MEDPresentation::getDispVar() {
802 return (_hideDataOutsideCustomRange ? _presentationThresolds[getThresholdIndex()]._thresholdDispVar : _dispVar);
806 Return _dispVar or _thresholdDispVar depending on _hideDataOutsideCustomRange flag:
807 _hideDataOutsideCustomRange == false : _dispVar is used
808 _hideDataOutsideCustomRange == true : _thresholdDispVar is used
810 const std::string& MEDPresentation::getLutVar() {
811 return (_hideDataOutsideCustomRange ? _presentationThresolds[getThresholdIndex()]._thresholdLutVar : _lutVar);
815 MEDPresentation::rescaleTransferFunction()
817 if (_hideDataOutsideCustomRange)
820 std::ostringstream oss;
823 case MEDCALC::SCALAR_BAR_ALL_TIMESTEPS:
824 oss << _dispVar << ".RescaleTransferFunctionToDataRangeOverTime();";
826 case MEDCALC::SCALAR_BAR_CURRENT_TIMESTEP:
827 oss << _dispVar << ".RescaleTransferFunctionToDataRange(False);";
829 case MEDCALC::SCALAR_BAR_CUSTOM_RANGE:
830 oss << _lutVar << ".RescaleTransferFunction("<< _scalarBarRangeArray[0]<<", "<< _scalarBarRangeArray[1]<<");";
833 STDLOG("MEDPresentation::getRescaleCommand(): invalid range!");
834 throw KERNEL::createSalomeException("MEDPresentation::getRescaleCommand(): invalid range!");
836 pushAndExecPyLine(oss.str()); oss.str("");
838 oss << _rangeVar << " = [" << _lutVar << ".RGBPoints[0], " << _lutVar << ".RGBPoints[-4]];";
839 execPyLine(oss.str());
841 //Update _scalarBarRange internal variable in case of rescaling to "Data Range" or "Data Range Over All Times"
842 if (_sbRange == MEDCALC::SCALAR_BAR_ALL_TIMESTEPS ||
843 _sbRange == MEDCALC::SCALAR_BAR_CURRENT_TIMESTEP) {
844 MEDPyLockWrapper lock;
845 PyObject * obj = getPythonObjectFromMain(_rangeVar.c_str());
846 if (obj && PyList_Check(obj)) {
847 PyObject* objL0 = PyList_GetItem(obj, 0);
848 PyObject* objL1 = PyList_GetItem(obj, 1);
849 if (PyFloat_Check(objL0)) {
850 double min = PyFloat_AsDouble(objL0);
851 _scalarBarRangeArray[0] = min;
853 if (PyFloat_Check(objL1)) {
854 double max = PyFloat_AsDouble(objL1);
855 _scalarBarRangeArray[1] = max;
858 setDoubleProperty(MEDPresentation::PROP_SCALAR_BAR_MIN_VALUE, _scalarBarRangeArray[0]);
859 setDoubleProperty(MEDPresentation::PROP_SCALAR_BAR_MAX_VALUE, _scalarBarRangeArray[1]);
861 // Adapt scalar bar title
865 MEDCALC::PresentationVisibility
866 MEDPresentation::presentationStateInActiveView() {
867 MEDPyLockWrapper lock;
868 MEDCALC::PresentationVisibility result = MEDCALC::PRESENTATION_NOT_IN_VIEW;
870 execPyLine("__isInView = ( " + getRenderViewVar() + " == pvs.GetActiveView() )");
871 PyObject * obj = getPythonObjectFromMain("__isInView");
873 if (obj && PyBool_Check(obj) && (obj == Py_True)) {
874 result = _presentationVisibility ? MEDCALC::PRESENTATION_VISIBLE : MEDCALC::PRESENTATION_INVISIBLE;
880 MEDPresentation::GeneratePythonId()
882 static int INIT_ID = 0;
886 bool MEDPresentation::isThresoldActive() const {
888 for (auto const& value : _presentationThresolds) {
889 active = active || value._active;
895 MEDPresentation::activateView()
897 MEDPyLockWrapper lock;
899 execPyLine("__alive = " + getRenderViewVar() + " in pvs.GetRenderViews()");
900 PyObject * obj = getPythonObjectFromMain("__alive");
902 if (obj && PyBool_Check(obj))
903 alive = (obj == Py_True);
906 // The view is still there,just activate it:
907 pushAndExecPyLine("pvs.SetActiveView(" + getRenderViewVar() + ");");
910 // The view disappeared, recreate it in a new layout. The transfer of the objects is to be done by the caller.
911 std::ostringstream oss;
912 oss << "pvs.servermanager.misc.ViewLayout(registrationGroup='layouts');";
913 pushAndExecPyLine(oss.str()); oss.str("");
914 oss << getRenderViewVar() << " = pvs.CreateView('RenderView');";
915 pushAndExecPyLine(oss.str()); oss.str("");
921 * Called when the view has been recreated (because the user closed it).
922 * All the objects and set up are re-shown in the new view (which is stored in the same Python variable).
925 MEDPresentation::recreateViewSetup()
927 bool prevHideDataOutsideCustomRange = _hideDataOutsideCustomRange;
928 _hideDataOutsideCustomRange = false;
933 rescaleTransferFunction();
934 _hideDataOutsideCustomRange = prevHideDataOutsideCustomRange;
936 resetCameraAndRender();
940 MEDPresentation::paravisDump() const
944 for (vector<string>::const_iterator it=_pythonCmds.begin(); it != _pythonCmds.end(); ++it)
953 * Query all available component names for the field associated with this presentation.
954 * Fills in all the corresponding string properties:
958 * and the number of components.
961 MEDPresentation::fillAvailableFieldComponents()
963 MEDPyLockWrapper lock; // GIL!
964 std::string typ = getScriptCellType();
966 std::ostringstream oss;
967 oss << "__nbCompo = " << _srcObjVar << "." << typ << ".GetArray('" << _fieldName << "').GetNumberOfComponents();";
968 execPyLine(oss.str());
969 PyObject* p_obj = getPythonObjectFromMain("__nbCompo");
971 if (p_obj && PyLong_Check(p_obj))
972 nbCompo = PyLong_AS_LONG(p_obj);
975 STDLOG("Unexpected Python error");
976 throw KERNEL::createSalomeException("Unexpected Python error");
978 _nbComponents = nbCompo;
979 _nbComponentsInThresholdInput = _nbComponents;
980 setIntProperty(MEDPresentation::PROP_NB_COMPONENTS, nbCompo);
982 // if the field is not a vector (2 or 3 components), select the first component of the tensor,
983 // like in WidgetPresentationParameters::setComponents
984 if (!(nbCompo > 1 && nbCompo <= 3))
985 _selectedComponentIndex = 0;
987 std::map<std::string, long> aCompoMap;
988 std::vector <std::string> aCompos;
989 for (long i = 0; i<nbCompo; i++)
991 std::ostringstream oss2;
992 oss2 << "__compo = " << _srcObjVar << "." << typ << ".GetArray('" << _fieldName << "').GetComponentName(" << i << ");";
993 execPyLine(oss2.str());
994 PyObject* p_obj = getPythonObjectFromMain("__compo");
996 if (p_obj && PyUnicode_Check(p_obj))
997 #if PY_VERSION_HEX < 0x030c0000 // See PEP-623
998 compo = std::string(Py_EncodeLocale(PyUnicode_AS_UNICODE(p_obj), NULL)); // pointing to internal Python memory, so make a copy!!
1000 compo = std::string(Py_EncodeLocale(PyUnicode_AsWideCharString(p_obj,NULL), NULL));
1004 STDLOG("Unexpected Python error");
1005 throw KERNEL::createSalomeException("Unexpected Python error");
1007 if (aCompoMap.find(compo) == aCompoMap.end()) {
1008 aCompoMap.insert(std::pair<std::string, int>(compo, 1));
1009 aCompos.push_back(compo);
1012 if (aCompoMap[compo] == 1) {
1013 for (std::vector<std::string>::size_type ii = 0; ii != aCompos.size(); ii++) {
1014 // Modify the previous occurrence
1015 if (aCompos[ii] == compo) {
1016 std::ostringstream oss_m;
1017 oss_m << compo << "(" << 1 << ")";
1018 aCompos[ii] = oss_m.str();
1022 std::ostringstream oss_n;
1023 oss_n << compo << "(" << 2 << ")";
1024 aCompos.push_back(oss_n.str());
1026 else if (aCompoMap[compo] > 1) {
1027 auto val = aCompoMap[compo];
1029 std::ostringstream oss_n;
1030 oss_n << compo << "(" << val << ")";
1031 aCompos.push_back(oss_n.str());
1033 aCompoMap[compo] = aCompoMap[compo] + 1;
1036 std::string aCopy = _programmableVar;
1037 std::string id = aCopy.replace(aCopy.find(PROGRAMMABLE), std::string(aCopy).length() - 1, "");
1039 std::vector<std::string>::size_type up = (nbCompo > 1) ? nbCompo + 1 : nbCompo;
1040 for (std::vector<std::string>::size_type i = 0; i != up; i++) {
1041 std::ostringstream oss_p;
1042 if (i != 0 || nbCompo == 1) {
1043 std::vector<std::string>::size_type idx = (nbCompo > 1) ? i - 1 : i;
1044 oss_p << MEDPresentation::PROP_COMPONENT << idx;
1045 setStringProperty(oss_p.str(), aCompos[idx]);
1047 std::ostringstream oss_thd, oss_th, oss_thl;
1048 oss_th << "__threshold" << id <<"_"<<i;
1049 oss_thd << "__thresholdDisp" << id << "_" << i;
1050 oss_thl << "__thresholdLut" << id << "_" << i;
1051 ComponentThresold ct = ComponentThresold();
1052 ct._thresholdVar = oss_th.str();
1053 ct._thresholdDispVar = oss_thd.str();
1054 ct._thresholdLutVar = oss_thl.str();
1055 _presentationThresolds.push_back(ct);
1059 std::string MEDPresentation::getThresholdFieldName() const {
1060 std::string result = getFieldName();
1061 if (_nbComponentsInThresholdInput > 1 && _hideDataOutsideCustomRange) {
1062 std::ostringstream oss;
1063 if (_selectedComponentIndex == -1) {
1064 oss << _fieldName << "_magnitude";
1067 oss << _fieldName << "_" << _selectedComponentIndex + 1;
1074 std::string MEDPresentation::getFieldName() const {
1078 std::string MEDPresentation::toScriptCellType(const std::string& pvType) {
1079 std::string typ = "";
1080 if (pvType == "CELLS") {
1083 else if (pvType == "POINTS") {
1087 std::string msg("Unsupported spatial discretisation: " + pvType);
1089 throw KERNEL::createSalomeException(msg.c_str());
1094 std::string MEDPresentation::getScriptCellType() const {
1095 return toScriptCellType(_pvFieldType);
1099 * In case where a CELLS field needs to be converted to POINT field.
1100 * This updates the source object to become the result of the CellDatatoPointData filter.
1103 MEDPresentation::applyCellToPointIfNeeded()
1105 if (_pvFieldType == "CELLS")
1107 std::ostringstream oss, oss2;
1108 // Apply Cell data to point data:
1109 oss2 << "__srcObj" << GeneratePythonId();
1110 oss << oss2.str() << " = pvs.CellDatatoPointData(Input=" << _srcObjVar << ");";
1111 pushAndExecPyLine(oss.str()); oss.str("");
1112 // Now the source becomes the result of the CellDatatoPointData:
1113 _srcObjVar = oss2.str();
1118 * Delete threshold filters and programmable filter
1121 MEDPresentation::deleteThresholds() {
1122 std::ostringstream oss;
1123 for (auto& value : _presentationThresolds) {
1124 if (value._active) {
1125 oss << "pvs.Hide(" << value._thresholdVar << ");";
1127 if (value._thresholdInitialized) {
1128 oss << "pvs.Delete(" << value._thresholdVar <<");";
1132 if (_programmableInitialized) {
1133 oss << "pvs.Delete(" << _programmableVar << ");";
1134 _programmableInitialized = false;
1136 pushAndExecPyLine(oss.str());
1140 // * Convert a vector field into a 3D vector field:
1141 // * - if the vector field is already 3D, nothing to do
1142 // * - if it is 2D, then add a null component
1143 // * - otherwise (tensor field, scalar field) throw
1146 //MEDPresentation::convertTo3DVectorField()
1148 // std::ostringstream oss, oss1, oss2, oss3;
1150 // int nbCompo = getIntProperty(MEDPresentation::PROP_NB_COMPONENTS);
1151 // if (nbCompo < 2 || nbCompo > 3)
1153 // oss << "The field '" << _fieldName << "' must have 2 or 3 components for this presentation!";
1154 // STDLOG(oss.str());
1155 // throw KERNEL::createSalomeException(oss.str().c_str());
1157 // if (nbCompo == 3)
1160 // // Apply calculator:
1161 // oss2 << "__srcObj" << GeneratePythonId();
1162 // oss << oss2.str() << " = pvs.Calculator(Input=" << _srcObjVar << ");";
1163 // pushAndExecPyLine(oss.str()); oss.str("");
1164 // // Now the source becomes the result of the CellDatatoPointData:
1165 // _srcObjVar = oss2.str();
1167 // if(_pvFieldType == "CELLS")
1168 // typ = "Cell Data";
1169 // else if(_pvFieldType == "POINTS")
1170 // typ = "Point Data";
1173 // oss3 << "Field '" << _fieldName << "' has invalid field type";
1174 // STDLOG(oss3.str());
1175 // throw KERNEL::createSalomeException(oss3.str().c_str());
1177 // oss << _srcObjVar << ".AttributeMode = '" << typ << "';";
1178 // pushAndExecPyLine(oss.str()); oss.str("");
1179 // oss << _srcObjVar << ".ResultArrayName = '" << _fieldName << "_CALC';"; // will never be needed I think
1180 // pushAndExecPyLine(oss.str()); oss.str("");
1181 // oss << _srcObjVar << ".Function = '" << _fieldName << "_0*iHat + " << _fieldName << "_1*jHat + 0.0*zHat';";
1182 // pushAndExecPyLine(oss.str()); oss.str("");