1 // Copyright (C) 2015-2016 CEA/DEN, EDF R&D, OPEN CASCADE
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 // File : MeasureGUI_ShapeStatisticsDlg.cxx
21 // Author : Alexander KOVALEV, OPEN CASCADE S.A.S.
24 #include "MeasureGUI_ShapeStatisticsDlg.h"
28 #include <GEOMUtils_ShapeStatistics.hxx>
29 #include <GeometryGUI.h>
33 #include <SUIT_Desktop.h>
34 #include <SUIT_MessageBox.h>
35 #include <SUIT_Session.h>
36 #include <SUIT_ResourceMgr.h>
37 #include <SUIT_ViewManager.h>
38 #include <SUIT_ViewWindow.h>
40 #include <LightApp_SelectionMgr.h>
42 #include <SalomeApp_Application.h>
44 #include <Plot2d_Histogram.h>
45 #include <Plot2d_ViewFrame.h>
46 #include <Plot2d_ViewModel.h>
47 #include <Plot2d_ViewWindow.h>
51 #include <QGridLayout>
52 #include <QPushButton>
56 #include <QtxValidator.h>
59 #include <TopoDS_Shape.hxx>
61 #include <GEOMImpl_Types.hxx>
63 //===========================================================================
64 // class : MeasureGUI_ShapeStatisticsDlg()
65 //===========================================================================
66 MeasureGUI_ShapeStatisticsDlg::MeasureGUI_ShapeStatisticsDlg( QWidget* parent, TopoDS_Shape aShape, TopAbs_ShapeEnum aSubShapeType )
67 : GEOMBase_Helper( SUIT_Session::session()->activeApplication()->desktop() ),
71 myShapes.push_back( aShape );
73 QIcon iconSelect( SUIT_Session::session()->resourceMgr()->loadPixmap( "GEOM", tr( "ICON_SELECT" ) ) );
75 setWindowTitle( tr( "GEOM_SHAPE_STATISTICS" ) );
76 setAttribute( Qt::WA_DeleteOnClose );
78 myApp = dynamic_cast< SalomeApp_Application* >( SUIT_Session::session()->activeApplication() );
80 QVBoxLayout* topLayout = new QVBoxLayout( this );
82 QGridLayout* settingsLayout = new QGridLayout();
84 /********************** Selected Objects **********************/
86 QLabel* objsLabel = new QLabel( tr( "GEOM_SELECTED_OBJECTS" ), this );
87 QPushButton* selBtn = new QPushButton( this );
88 selBtn->setIcon( iconSelect );
89 myEditMainShape = new QLineEdit( this );
90 myEditMainShape->setReadOnly(true);
92 settingsLayout->addWidget( objsLabel, 0, 0 );
93 settingsLayout->addWidget( selBtn, 0, 1 );
94 settingsLayout->addWidget( myEditMainShape, 0, 2 );
96 if ( !aShape.IsNull() ) {
99 myEditMainShape->hide();
102 /********************** Type **********************/
104 QLabel* typeLabel = new QLabel( tr( "GEOM_SHAPE_STATISTICS_TYPE" ), this );
105 myCBTypes = new QtxComboBox( this );
106 myCBTypes->setCleared( true );
107 if ( aSubShapeType != TopAbs_SHAPE ) {
108 fillTypes( aSubShapeType == TopAbs_EDGE,
109 aSubShapeType == TopAbs_FACE,
110 aSubShapeType == TopAbs_SOLID );
111 myCBTypes->setEnabled( false );
114 settingsLayout->addWidget( typeLabel, 1, 0 );
115 settingsLayout->addWidget( myCBTypes, 1, 2 );
117 /********************** Number of intervals **********************/
119 QLabel* nbIntervalsLabel = new QLabel( tr( "GEOM_SHAPE_STATISTICS_NB_INTERVALS" ), this );
120 myNbIntervals = new QtxIntSpinBox( 1, 1000, 1, this );
121 myNbIntervals->setValue( 10 );
123 settingsLayout->addWidget( nbIntervalsLabel, 2, 0 );
124 settingsLayout->addWidget( myNbIntervals, 2, 2 );
126 /********************** Scalar Range **********************/
128 myScalarRangeBox = new QGroupBox( tr( "GEOM_SHAPE_STATISTICS_SCALAR_RANGE" ), this );
129 myScalarRangeBox->setCheckable( true );
130 myScalarRangeBox->setChecked( false );
131 QLabel* minLabel = new QLabel( tr( "GEOM_SHAPE_STATISTICS_MIN" ), this );
132 myMin = new QLineEdit( this );
133 QtxDoubleValidator* aValid = new QtxDoubleValidator( this );
134 aValid->setBottom( 0.0 );
135 myMin->setValidator( aValid );
136 QLabel* maxLabel = new QLabel( tr( "GEOM_SHAPE_STATISTICS_MAX" ), this );
137 myMax = new QLineEdit( this );
138 myMax->setValidator( aValid );
140 QPushButton* buttonCompute = new QPushButton( tr( "GEOM_SHAPE_STATISTICS_COMPUTE" ), this );
141 connect( buttonCompute, SIGNAL( clicked() ), this, SLOT( clickOnCompute() ) );
143 QGridLayout* scalarRangeLayout = new QGridLayout();
144 scalarRangeLayout->setMargin( 11 ); settingsLayout->setSpacing( 6 );
146 scalarRangeLayout->addWidget( minLabel, 0, 0 );
147 scalarRangeLayout->addWidget( myMin, 0, 1 );
148 scalarRangeLayout->addWidget( maxLabel, 1, 0 );
149 scalarRangeLayout->addWidget( myMax, 1, 1 );
150 scalarRangeLayout->addWidget( buttonCompute, 0, 2, 2, 1 );
152 myScalarRangeBox->setLayout( scalarRangeLayout );
154 /********************** Buttons **********************/
156 myButtonPlot = new QPushButton( tr( "GEOM_PLOT_DISTRIBUTION" ), this );
157 myButtonPlot->setDefault( true );
158 myButtonCreateGr = new QPushButton( tr( "GEOM_SHAPE_STATISTICS_CREATE_GROUPS" ), this );
159 QPushButton* buttonClose = new QPushButton( tr( "GEOM_BUT_CLOSE" ), this );
160 QPushButton* buttonHelp = new QPushButton( tr( "GEOM_BUT_HELP" ), this );
162 QHBoxLayout* buttonsLayout = new QHBoxLayout();
163 buttonsLayout->addWidget( myButtonPlot );
164 buttonsLayout->addWidget( myButtonCreateGr );
165 buttonsLayout->addWidget( buttonClose );
166 buttonsLayout->addWidget( buttonHelp );
168 if ( !aShape.IsNull() ) {
169 myButtonCreateGr->hide();
171 /********************** Layouting **********************/
173 topLayout->addLayout( settingsLayout );
174 topLayout->addWidget( myScalarRangeBox );
175 topLayout->addLayout( buttonsLayout );
177 // Signals and slots connections
179 connect( selBtn, SIGNAL( clicked() ), this, SLOT( onEditMainShape() ) );
181 connect( myButtonPlot, SIGNAL( clicked() ), this, SLOT( clickOnPlot() ) );
182 connect( myButtonCreateGr, SIGNAL( clicked() ), this, SLOT( clickOnCreateGroups() ) );
184 connect( buttonClose, SIGNAL( clicked() ), this, SLOT( reject() ) );
185 connect( buttonHelp, SIGNAL( clicked() ), this, SLOT( clickOnHelp() ) );
187 connect(myApp->selectionMgr(),
188 SIGNAL(currentSelectionChanged()), this, SLOT(onEditMainShape()));
190 if ( aShape.IsNull() )
194 //===========================================================================
195 // function : ~MeasureGUI_ShapeStatisticsDlg()
196 // purpose : Destroys the object and frees any allocated resources
197 //===========================================================================
198 MeasureGUI_ShapeStatisticsDlg::~MeasureGUI_ShapeStatisticsDlg()
202 //=================================================================================
203 // function : createOperation
205 //=================================================================================
206 GEOM::GEOM_IOperations_ptr MeasureGUI_ShapeStatisticsDlg::createOperation()
208 return getGeomEngine()->GetIGroupOperations();
211 #define RETURN_WITH_MSG(a, b) \
217 //================================================================
218 // Function : getFather
219 // Purpose : Get father object for object to be added in study
220 // (called with addInStudy method)
221 //================================================================
222 GEOM::GEOM_Object_ptr MeasureGUI_ShapeStatisticsDlg::getFather(GEOM::GEOM_Object_ptr theObj)
224 GEOM::GEOM_Object_var aFatherObj;
225 if (theObj->GetType() == GEOM_GROUP) {
226 GEOM::GEOM_IGroupOperations_var anOper = GEOM::GEOM_IGroupOperations::_narrow(getOperation());
227 aFatherObj = anOper->GetMainShape(theObj);
229 return aFatherObj._retn();
232 //=================================================================================
233 // function : getSourceObjects
234 // purpose : virtual method to get source objects
235 //=================================================================================
236 QList<GEOM::GeomObjPtr> MeasureGUI_ShapeStatisticsDlg::getSourceObjects()
238 QList<GEOM::GeomObjPtr> res;
243 //=================================================================================
244 // function : onEditMainShape()
245 // purpose : called when selection button was clicked
246 //=================================================================================
247 void MeasureGUI_ShapeStatisticsDlg::onEditMainShape()
249 // restore initial parameters for dialog box
250 myEditMainShape->setText("");
251 myEditMainShape->setFocus();
253 //get shapes from selection
254 QList<GEOM::GeomObjPtr> selShapes = getSelected( TopAbs_SHAPE, -1 );
256 myButtonPlot->setEnabled( !selShapes.isEmpty() );
257 myButtonCreateGr->setEnabled( selShapes.count() == 1 );
259 if ( !selShapes.isEmpty() ) {
260 if ( selShapes.count() == 1 )
261 myMainObj = selShapes[0];
262 QString aName = selShapes.count() > 1 ? QString( "%1_objects").arg( selShapes.count() ) : GEOMBase::GetName( myMainObj.get() );
263 myEditMainShape->setText( aName );
266 updateTypes( selShapes );
269 //=================================================================================
270 // function : currentType()
271 // purpose : returns currently selected type of shapes in 'Type' combobox
272 //=================================================================================
273 void MeasureGUI_ShapeStatisticsDlg::fillTypes( bool hasEdges, bool hasFaces, bool hasSolids )
276 myCBTypes->addItem( tr("GEOM_SHAPE_STATISTICS_LENGTH"), (int)TopAbs_EDGE );
278 myCBTypes->addItem( tr("GEOM_SHAPE_STATISTICS_AREA"), (int)TopAbs_FACE );
280 myCBTypes->addItem( tr("GEOM_SHAPE_STATISTICS_VOLUME"), (int)TopAbs_SOLID );
282 myCBTypes->setEnabled( myCBTypes->count() > 0 );
285 //=================================================================================
286 // function : updateTypes()
287 // purpose : update 'Type' combobox with available types
288 //=================================================================================
289 void MeasureGUI_ShapeStatisticsDlg::updateTypes( QList<GEOM::GeomObjPtr> theShapes )
292 myCBTypes->setEnabled( false );
294 int hasEdges = -1, hasFaces = -1, hasSolids = -1;
297 // get types of the shapes and its sub-shapes
298 foreach( GEOM::GeomObjPtr aShapePtr, theShapes ) {
303 if ( !GEOMBase::GetShape( aShapePtr.get(), aShape ) || aShape.IsNull() )
306 myShapes.push_back( aShape );
308 GEOM::ListOfLong_var aSubShapes;
309 GEOM::GEOM_IShapesOperations_var aShOp = getGeomEngine()->GetIShapesOperations();
311 hasEdges = aShOp->NumberOfSubShapes( aShapePtr.get(), TopAbs_EDGE ) > 0;
313 hasFaces = aShOp->NumberOfSubShapes( aShapePtr.get(), TopAbs_FACE ) > 0;
314 if ( hasSolids != 0 )
315 hasSolids = aShOp->NumberOfSubShapes( aShapePtr.get(), TopAbs_SOLID ) > 0;
317 fillTypes( hasEdges, hasFaces, hasSolids );
320 //=================================================================================
321 // function : currentType()
322 // purpose : returns currently selected type of shapes in 'Type' combobox
323 //=================================================================================
324 TopAbs_ShapeEnum MeasureGUI_ShapeStatisticsDlg::currentType()
326 return (TopAbs_ShapeEnum)( myCBTypes->itemData( myCBTypes->currentIndex() ).toInt() );
329 //=================================================================================
330 // function : clickOnPlot()
331 // purpose : called when Plot button was clicked
332 //=================================================================================
333 bool MeasureGUI_ShapeStatisticsDlg::isValid(QString& theMessage)
335 if ( myScalarRangeBox->isChecked() ) {
336 RETURN_WITH_MSG( !myMin->text().isEmpty(), tr("GEOM_SHAPE_STATISTICS_MIN_ERROR") );
337 RETURN_WITH_MSG( !myMax->text().isEmpty(), tr("GEOM_SHAPE_STATISTICS_MAX_ERROR") );
338 RETURN_WITH_MSG( myMin->text().toDouble() <= myMax->text().toDouble(), tr("GEOM_SHAPE_STATISTICS_MIN_MAX_ERROR") );
342 //=================================================================================
343 // function : clickOnPlot()
344 // purpose : called when Plot button was clicked
345 //=================================================================================
346 void MeasureGUI_ShapeStatisticsDlg::clickOnPlot()
348 GEOMUtils::Range aRange;
349 if ( myScalarRangeBox->isChecked() ) {
351 if ( !isValid( msg ) ) {
355 aRange.min = myMin->text().toDouble();
356 aRange.max = myMax->text().toDouble();
358 aRange.min = -1.0; // flag that range is empty
359 aRange.max = -1.0; // flag that range is empty
362 GEOMUtils::Distribution aShapesDistr =
363 GEOMUtils::ComputeDistribution( myShapes, currentType(), myNbIntervals->value(), aRange );
365 QList<double> xVals, yVals;
366 double width = -1, min = -1;
367 double xmin = 1e+32, xmax = 0.0, ymax = 0.0;
369 GEOMUtils::Distribution::const_iterator it;
370 for (it = aShapesDistr.begin(); it != aShapesDistr.end(); it++) {
371 GEOMUtils::Range ran = *it;
372 if ( width < 0 ) width = ran.max - ran.min; // bar width
373 if ( min < 0 ) min = ran.min; // global min
374 xVals << width / 2. + i*width + min; // get a middle of bar
376 // get global boundary max values
377 if ( ran.min < xmin ) xmin = ran.min;
378 if ( ran.max > xmax ) xmax = ran.max;
379 if ( ran.count > ymax ) ymax = ran.count;
383 // plot the computed distribution
384 SUIT_ViewManager* aViewManager = myApp->getViewManager( Plot2d_Viewer::Type(), true ); // create if necessary
387 Plot2d_ViewWindow* aViewWnd = dynamic_cast<Plot2d_ViewWindow*>(aViewManager->getActiveView());
390 Plot2d_ViewFrame* aPlot = aViewWnd->getViewFrame();
396 // create or reuse histogram
398 myHistogram = new Plot2d_Histogram();
400 myHistogram->clearAllPoints();
401 // set histogram parameters
402 myHistogram->setData( xVals, yVals );
404 myHistogram->setWidth( width );
405 myHistogram->setAutoAssign(true);
406 myHistogram->setName( myEditMainShape->text() );
407 myHistogram->setHorTitle( myCBTypes->currentText() );
408 myHistogram->setVerTitle( tr("GEOM_SHAPE_STATISTICS_DISTRIBUTION_NB_ENT") );
409 myHistogram->setColor( QColor(0, 85, 0) );
411 aPlot->displayObject( myHistogram, true );
412 if ( width == 0.0 ) // only one X value
415 aPlot->fitData( 0, xmin, xmax, 0.0, ymax );
418 //=================================================================================
419 // function : clickOnCompute()
420 // purpose : called when Compute button was clicked
421 //=================================================================================
422 void MeasureGUI_ShapeStatisticsDlg::clickOnCompute()
424 GEOMUtils::Range aRange;
425 aRange.min = -1.0; // flag that range is empty
426 aRange.max = -1.0; // flag that range is empty
427 std::map<int,double> measures = GEOMUtils::ComputeMeasures( myShapes, currentType(), aRange );
428 if ( measures.size() != 0 ) {
429 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
430 int aPrecision = resMgr->integerValue( "Geometry", "length_precision", 6 );
431 myMin->setText( DlgRef::PrintDoubleValue( aRange.min, aPrecision ) );
432 myMax->setText( DlgRef::PrintDoubleValue( aRange.max, aPrecision ) );
436 //=================================================================================
437 // function : clickOnCreateGroups()
438 // purpose : called when Create Groups button was clicked
439 //=================================================================================
440 void MeasureGUI_ShapeStatisticsDlg::clickOnCreateGroups()
442 onAccept(false, false, false);
445 //=================================================================================
446 // function : execute(ObjectList& objects)
448 //=================================================================================
449 bool MeasureGUI_ShapeStatisticsDlg::execute(ObjectList& objects)
451 if ( myMainObj.isNull() )
454 GEOM::GroupOpPtr anOper = GEOM::GEOM_IGroupOperations::_narrow(getOperation());
456 GEOMUtils::Range aRange;
457 if ( myScalarRangeBox->isChecked() ) {
459 if ( !isValid( msg ) ) {
463 aRange.min = myMin->text().toDouble();
464 aRange.max = myMax->text().toDouble();
466 aRange.min = -1.0; // flag that range is empty
467 aRange.max = -1.0; // flag that range is empty
470 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
471 int aPrecision = resMgr->integerValue( "Geometry", "length_precision", 6 );
472 QString aTypePrefix = myCBTypes->currentText().replace(' ', '_');
473 QString objIOR, aMin, aMax, aGroupName;
475 GEOMUtils::Distribution aShapesDistr =
476 GEOMUtils::ComputeDistribution( myShapes, currentType(), myNbIntervals->value(), aRange );
480 GEOMUtils::Distribution::const_iterator it;
481 for (it = aShapesDistr.begin(); it != aShapesDistr.end(); it++) {
482 std::list<long> idList = (*it).indices;
483 int nn = idList.size();
485 GEOM::ListOfLong_var aNewList = new GEOM::ListOfLong;
486 aNewList->length(nn);
488 std::list<long>::const_iterator id_it;
489 for ( id_it = idList.begin(); id_it != idList.end(); id_it++ ) {
490 aNewList[ii++] = *id_it;
493 // Create an empty group
494 GEOM::GEOM_Object_var aGroup;
495 aGroup = anOper->CreateGroup( myMainObj.get(), currentType() );
497 if (CORBA::is_nil(aGroup) || !anOper->IsDone())
500 // Add sub-shapes into group
501 anOper->UnionIDs(aGroup, aNewList);
502 if (!anOper->IsDone())
506 aMin = DlgRef::PrintDoubleValue( (*it).min, aPrecision );
507 aMax = DlgRef::PrintDoubleValue( (*it).max, aPrecision );
508 aGroupName = aTypePrefix + "_" + aMin + "_" + aMax;
509 GEOMBase::PublishSubObject( aGroup, aGroupName );
511 // this is needed just to avoid error message
512 objects.push_back(aGroup._retn());
518 SUIT_MessageBox::information( this, tr( "INF_INFO" ), tr( "GEOM_MSG_GROUPS_CREATED" ).arg( nbGroups ) );
523 //=================================================================================
524 // function : clickOnHelp()
525 // purpose : called when Help button was clicked
526 //=================================================================================
527 void MeasureGUI_ShapeStatisticsDlg::clickOnHelp()
529 GeometryGUI* aGeomGUI = dynamic_cast<GeometryGUI*>( myApp->module( "Geometry" ) );
530 myApp->onHelpContextModule( aGeomGUI ? myApp->moduleName( aGeomGUI->moduleName() ) : QString(""), "shape_statistics_operation_page.html" );