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>
43 #include <SalomeApp_Study.h>
45 #include <Plot2d_Histogram.h>
46 #include <Plot2d_ViewFrame.h>
47 #include <Plot2d_ViewModel.h>
48 #include <Plot2d_ViewWindow.h>
52 #include <QGridLayout>
53 #include <QPushButton>
57 #include <QtxValidator.h>
60 #include <TopoDS_Shape.hxx>
62 #include <GEOMImpl_Types.hxx>
64 //===========================================================================
65 // class : MeasureGUI_ShapeStatisticsDlg()
66 //===========================================================================
67 MeasureGUI_ShapeStatisticsDlg::MeasureGUI_ShapeStatisticsDlg( QWidget* parent, TopoDS_Shape aShape, TopAbs_ShapeEnum aSubShapeType )
68 : GEOMBase_Helper( SUIT_Session::session()->activeApplication()->desktop() ),
72 myShapes.push_back( aShape );
74 QIcon iconSelect( SUIT_Session::session()->resourceMgr()->loadPixmap( "GEOM", tr( "ICON_SELECT" ) ) );
76 setWindowTitle( tr( "GEOM_SHAPE_STATISTICS" ) );
77 setAttribute( Qt::WA_DeleteOnClose );
79 myApp = dynamic_cast< SalomeApp_Application* >( SUIT_Session::session()->activeApplication() );
81 QVBoxLayout* topLayout = new QVBoxLayout( this );
83 QGridLayout* settingsLayout = new QGridLayout();
85 /********************** Selected Objects **********************/
87 QLabel* objsLabel = new QLabel( tr( "GEOM_SELECTED_OBJECTS" ), this );
88 QPushButton* selBtn = new QPushButton( this );
89 selBtn->setIcon( iconSelect );
90 myEditMainShape = new QLineEdit( this );
91 myEditMainShape->setReadOnly(true);
93 settingsLayout->addWidget( objsLabel, 0, 0 );
94 settingsLayout->addWidget( selBtn, 0, 1 );
95 settingsLayout->addWidget( myEditMainShape, 0, 2 );
97 if ( !aShape.IsNull() ) {
100 myEditMainShape->hide();
103 /********************** Type **********************/
105 QLabel* typeLabel = new QLabel( tr( "GEOM_SHAPE_STATISTICS_TYPE" ), this );
106 myCBTypes = new QtxComboBox( this );
107 myCBTypes->setCleared( true );
108 if ( aSubShapeType != TopAbs_SHAPE ) {
109 fillTypes( aSubShapeType == TopAbs_EDGE,
110 aSubShapeType == TopAbs_FACE,
111 aSubShapeType == TopAbs_SOLID );
112 myCBTypes->setEnabled( false );
115 settingsLayout->addWidget( typeLabel, 1, 0 );
116 settingsLayout->addWidget( myCBTypes, 1, 2 );
118 /********************** Number of intervals **********************/
120 QLabel* nbIntervalsLabel = new QLabel( tr( "GEOM_SHAPE_STATISTICS_NB_INTERVALS" ), this );
121 myNbIntervals = new QtxIntSpinBox( 1, 1000, 1, this );
122 myNbIntervals->setValue( 10 );
124 settingsLayout->addWidget( nbIntervalsLabel, 2, 0 );
125 settingsLayout->addWidget( myNbIntervals, 2, 2 );
127 /********************** Scalar Range **********************/
129 myScalarRangeBox = new QGroupBox( tr( "GEOM_SHAPE_STATISTICS_SCALAR_RANGE" ), this );
130 myScalarRangeBox->setCheckable( true );
131 myScalarRangeBox->setChecked( false );
132 QLabel* minLabel = new QLabel( tr( "GEOM_SHAPE_STATISTICS_MIN" ), this );
133 myMin = new QLineEdit( this );
134 QtxDoubleValidator* aValid = new QtxDoubleValidator( this );
135 aValid->setBottom( 0.0 );
136 myMin->setValidator( aValid );
137 QLabel* maxLabel = new QLabel( tr( "GEOM_SHAPE_STATISTICS_MAX" ), this );
138 myMax = new QLineEdit( this );
139 myMax->setValidator( aValid );
141 QPushButton* buttonCompute = new QPushButton( tr( "GEOM_SHAPE_STATISTICS_COMPUTE" ), this );
142 connect( buttonCompute, SIGNAL( clicked() ), this, SLOT( clickOnCompute() ) );
144 QGridLayout* scalarRangeLayout = new QGridLayout();
145 scalarRangeLayout->setMargin( 11 ); settingsLayout->setSpacing( 6 );
147 scalarRangeLayout->addWidget( minLabel, 0, 0 );
148 scalarRangeLayout->addWidget( myMin, 0, 1 );
149 scalarRangeLayout->addWidget( maxLabel, 1, 0 );
150 scalarRangeLayout->addWidget( myMax, 1, 1 );
151 scalarRangeLayout->addWidget( buttonCompute, 0, 2, 2, 1 );
153 myScalarRangeBox->setLayout( scalarRangeLayout );
155 /********************** Buttons **********************/
157 myButtonPlot = new QPushButton( tr( "GEOM_PLOT_DISTRIBUTION" ), this );
158 myButtonPlot->setDefault( true );
159 myButtonCreateGr = new QPushButton( tr( "GEOM_SHAPE_STATISTICS_CREATE_GROUPS" ), this );
160 QPushButton* buttonClose = new QPushButton( tr( "GEOM_BUT_CLOSE" ), this );
161 QPushButton* buttonHelp = new QPushButton( tr( "GEOM_BUT_HELP" ), this );
163 QHBoxLayout* buttonsLayout = new QHBoxLayout();
164 buttonsLayout->addWidget( myButtonPlot );
165 buttonsLayout->addWidget( myButtonCreateGr );
166 buttonsLayout->addWidget( buttonClose );
167 buttonsLayout->addWidget( buttonHelp );
169 if ( !aShape.IsNull() ) {
170 myButtonCreateGr->hide();
172 /********************** Layouting **********************/
174 topLayout->addLayout( settingsLayout );
175 topLayout->addWidget( myScalarRangeBox );
176 topLayout->addLayout( buttonsLayout );
178 // Signals and slots connections
180 connect( selBtn, SIGNAL( clicked() ), this, SLOT( onEditMainShape() ) );
182 connect( myButtonPlot, SIGNAL( clicked() ), this, SLOT( clickOnPlot() ) );
183 connect( myButtonCreateGr, SIGNAL( clicked() ), this, SLOT( clickOnCreateGroups() ) );
185 connect( buttonClose, SIGNAL( clicked() ), this, SLOT( reject() ) );
186 connect( buttonHelp, SIGNAL( clicked() ), this, SLOT( clickOnHelp() ) );
188 connect(myApp->selectionMgr(),
189 SIGNAL(currentSelectionChanged()), this, SLOT(onEditMainShape()));
191 if ( aShape.IsNull() )
195 //===========================================================================
196 // function : ~MeasureGUI_ShapeStatisticsDlg()
197 // purpose : Destroys the object and frees any allocated resources
198 //===========================================================================
199 MeasureGUI_ShapeStatisticsDlg::~MeasureGUI_ShapeStatisticsDlg()
203 //=================================================================================
204 // function : createOperation
206 //=================================================================================
207 GEOM::GEOM_IOperations_ptr MeasureGUI_ShapeStatisticsDlg::createOperation()
209 return getGeomEngine()->GetIGroupOperations(getStudyId());
212 #define RETURN_WITH_MSG(a, b) \
218 //================================================================
219 // Function : getFather
220 // Purpose : Get father object for object to be added in study
221 // (called with addInStudy method)
222 //================================================================
223 GEOM::GEOM_Object_ptr MeasureGUI_ShapeStatisticsDlg::getFather(GEOM::GEOM_Object_ptr theObj)
225 GEOM::GEOM_Object_var aFatherObj;
226 if (theObj->GetType() == GEOM_GROUP) {
227 GEOM::GEOM_IGroupOperations_var anOper = GEOM::GEOM_IGroupOperations::_narrow(getOperation());
228 aFatherObj = anOper->GetMainShape(theObj);
230 return aFatherObj._retn();
233 //=================================================================================
234 // function : getSourceObjects
235 // purpose : virtual method to get source objects
236 //=================================================================================
237 QList<GEOM::GeomObjPtr> MeasureGUI_ShapeStatisticsDlg::getSourceObjects()
239 QList<GEOM::GeomObjPtr> res;
244 //=================================================================================
245 // function : onEditMainShape()
246 // purpose : called when selection button was clicked
247 //=================================================================================
248 void MeasureGUI_ShapeStatisticsDlg::onEditMainShape()
250 // restore initial parameters for dialog box
251 myEditMainShape->setText("");
252 myEditMainShape->setFocus();
254 //get shapes from selection
255 QList<GEOM::GeomObjPtr> selShapes = getSelected( TopAbs_SHAPE, -1 );
257 myButtonPlot->setEnabled( !selShapes.isEmpty() );
258 myButtonCreateGr->setEnabled( selShapes.count() == 1 );
260 if ( !selShapes.isEmpty() ) {
261 if ( selShapes.count() == 1 )
262 myMainObj = selShapes[0];
263 QString aName = selShapes.count() > 1 ? QString( "%1_objects").arg( selShapes.count() ) : GEOMBase::GetName( myMainObj.get() );
264 myEditMainShape->setText( aName );
267 updateTypes( selShapes );
270 //=================================================================================
271 // function : currentType()
272 // purpose : returns currently selected type of shapes in 'Type' combobox
273 //=================================================================================
274 void MeasureGUI_ShapeStatisticsDlg::fillTypes( bool hasEdges, bool hasFaces, bool hasSolids )
277 myCBTypes->addItem( tr("GEOM_SHAPE_STATISTICS_LENGTH"), (int)TopAbs_EDGE );
279 myCBTypes->addItem( tr("GEOM_SHAPE_STATISTICS_AREA"), (int)TopAbs_FACE );
281 myCBTypes->addItem( tr("GEOM_SHAPE_STATISTICS_VOLUME"), (int)TopAbs_SOLID );
283 myCBTypes->setEnabled( myCBTypes->count() > 0 );
286 //=================================================================================
287 // function : updateTypes()
288 // purpose : update 'Type' combobox with available types
289 //=================================================================================
290 void MeasureGUI_ShapeStatisticsDlg::updateTypes( QList<GEOM::GeomObjPtr> theShapes )
293 myCBTypes->setEnabled( false );
295 int hasEdges = -1, hasFaces = -1, hasSolids = -1;
298 // get types of the shapes and its sub-shapes
299 foreach( GEOM::GeomObjPtr aShapePtr, theShapes ) {
304 if ( !GEOMBase::GetShape( aShapePtr.get(), aShape ) || aShape.IsNull() )
307 myShapes.push_back( aShape );
309 GEOM::ListOfLong_var aSubShapes;
310 GEOM::GEOM_IShapesOperations_var aShOp = getGeomEngine()->GetIShapesOperations( getStudyId() );
312 hasEdges = aShOp->NumberOfSubShapes( aShapePtr.get(), TopAbs_EDGE ) > 0;
314 hasFaces = aShOp->NumberOfSubShapes( aShapePtr.get(), TopAbs_FACE ) > 0;
315 if ( hasSolids != 0 )
316 hasSolids = aShOp->NumberOfSubShapes( aShapePtr.get(), TopAbs_SOLID ) > 0;
318 fillTypes( hasEdges, hasFaces, hasSolids );
321 //=================================================================================
322 // function : currentType()
323 // purpose : returns currently selected type of shapes in 'Type' combobox
324 //=================================================================================
325 TopAbs_ShapeEnum MeasureGUI_ShapeStatisticsDlg::currentType()
327 return (TopAbs_ShapeEnum)( myCBTypes->itemData( myCBTypes->currentIndex() ).toInt() );
330 //=================================================================================
331 // function : clickOnPlot()
332 // purpose : called when Plot button was clicked
333 //=================================================================================
334 bool MeasureGUI_ShapeStatisticsDlg::isValid(QString& theMessage)
336 if ( myScalarRangeBox->isChecked() ) {
337 RETURN_WITH_MSG( !myMin->text().isEmpty(), tr("GEOM_SHAPE_STATISTICS_MIN_ERROR") )
338 RETURN_WITH_MSG( !myMax->text().isEmpty(), tr("GEOM_SHAPE_STATISTICS_MAX_ERROR") )
339 RETURN_WITH_MSG( myMin->text().toDouble() <= myMax->text().toDouble(), tr("GEOM_SHAPE_STATISTICS_MIN_MAX_ERROR") )
343 //=================================================================================
344 // function : clickOnPlot()
345 // purpose : called when Plot button was clicked
346 //=================================================================================
347 void MeasureGUI_ShapeStatisticsDlg::clickOnPlot()
349 GEOMUtils::Range aRange;
350 if ( myScalarRangeBox->isChecked() ) {
352 if ( !isValid( msg ) ) {
356 aRange.min = myMin->text().toDouble();
357 aRange.max = myMax->text().toDouble();
359 aRange.min = -1.0; // flag that range is empty
360 aRange.max = -1.0; // flag that range is empty
363 GEOMUtils::Distribution aShapesDistr =
364 GEOMUtils::ComputeDistribution( myShapes, currentType(), myNbIntervals->value(), aRange );
366 QList<double> xVals, yVals;
367 double width = -1, min = -1;
368 double xmin = 1e+32, xmax = 0.0, ymax = 0.0;
370 GEOMUtils::Distribution::const_iterator it;
371 for (it = aShapesDistr.begin(); it != aShapesDistr.end(); it++) {
372 GEOMUtils::Range ran = *it;
373 if ( width < 0 ) width = ran.max - ran.min; // bar width
374 if ( min < 0 ) min = ran.min; // global min
375 xVals << width / 2. + i*width + min; // get a middle of bar
377 // get global boundary max values
378 if ( ran.min < xmin ) xmin = ran.min;
379 if ( ran.max > xmax ) xmax = ran.max;
380 if ( ran.count > ymax ) ymax = ran.count;
384 // plot the computed distribution
385 SUIT_ViewManager* aViewManager = myApp->getViewManager( Plot2d_Viewer::Type(), true ); // create if necessary
388 Plot2d_ViewWindow* aViewWnd = dynamic_cast<Plot2d_ViewWindow*>(aViewManager->getActiveView());
391 Plot2d_ViewFrame* aPlot = aViewWnd->getViewFrame();
397 // create or reuse histogram
399 myHistogram = new Plot2d_Histogram();
401 myHistogram->clearAllPoints();
402 // set histogram parameters
403 myHistogram->setData( xVals, yVals );
405 myHistogram->setWidth( width );
406 myHistogram->setAutoAssign(true);
407 myHistogram->setName( myEditMainShape->text() );
408 myHistogram->setHorTitle( myCBTypes->currentText() );
409 myHistogram->setVerTitle( tr("GEOM_SHAPE_STATISTICS_DISTRIBUTION_NB_ENT") );
410 myHistogram->setColor( QColor(0, 85, 0) );
412 aPlot->displayObject( myHistogram, true );
413 if ( width == 0.0 ) // only one X value
416 aPlot->fitData( 0, xmin, xmax, 0.0, ymax );
419 //=================================================================================
420 // function : clickOnCompute()
421 // purpose : called when Compute button was clicked
422 //=================================================================================
423 void MeasureGUI_ShapeStatisticsDlg::clickOnCompute()
425 GEOMUtils::Range aRange;
426 aRange.min = -1.0; // flag that range is empty
427 aRange.max = -1.0; // flag that range is empty
428 std::map<int,double> measures = GEOMUtils::ComputeMeasures( myShapes, currentType(), aRange );
429 if ( measures.size() != 0 ) {
430 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
431 int aPrecision = resMgr->integerValue( "Geometry", "length_precision", 6 );
432 myMin->setText( DlgRef::PrintDoubleValue( aRange.min, aPrecision ) );
433 myMax->setText( DlgRef::PrintDoubleValue( aRange.max, aPrecision ) );
437 //=================================================================================
438 // function : clickOnCreateGroups()
439 // purpose : called when Create Groups button was clicked
440 //=================================================================================
441 void MeasureGUI_ShapeStatisticsDlg::clickOnCreateGroups()
443 onAccept(false, false, false);
446 //=================================================================================
447 // function : execute(ObjectList& objects)
449 //=================================================================================
450 bool MeasureGUI_ShapeStatisticsDlg::execute(ObjectList& objects)
452 if ( myMainObj.isNull() )
455 GEOM::GroupOpPtr anOper = GEOM::GEOM_IGroupOperations::_narrow(getOperation());
457 GEOMUtils::Range aRange;
458 if ( myScalarRangeBox->isChecked() ) {
460 if ( !isValid( msg ) ) {
464 aRange.min = myMin->text().toDouble();
465 aRange.max = myMax->text().toDouble();
467 aRange.min = -1.0; // flag that range is empty
468 aRange.max = -1.0; // flag that range is empty
471 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
472 int aPrecision = resMgr->integerValue( "Geometry", "length_precision", 6 );
473 QString aTypePrefix = myCBTypes->currentText().replace(' ', '_');
474 QString objIOR, aMin, aMax, aGroupName;
475 SalomeApp_Study* study = getStudy();
477 GEOMUtils::Distribution aShapesDistr =
478 GEOMUtils::ComputeDistribution( myShapes, currentType(), myNbIntervals->value(), aRange );
482 GEOMUtils::Distribution::const_iterator it;
483 for (it = aShapesDistr.begin(); it != aShapesDistr.end(); it++) {
484 std::list<long> idList = (*it).indices;
485 int nn = idList.size();
487 GEOM::ListOfLong_var aNewList = new GEOM::ListOfLong;
488 aNewList->length(nn);
490 std::list<long>::const_iterator id_it;
491 for ( id_it = idList.begin(); id_it != idList.end(); id_it++ ) {
492 aNewList[ii++] = *id_it;
495 // Create an empty group
496 GEOM::GEOM_Object_var aGroup;
497 aGroup = anOper->CreateGroup( myMainObj.get(), currentType() );
499 if (CORBA::is_nil(aGroup) || !anOper->IsDone())
502 // Add sub-shapes into group
503 anOper->UnionIDs(aGroup, aNewList);
504 if (!anOper->IsDone())
508 aMin = DlgRef::PrintDoubleValue( (*it).min, aPrecision );
509 aMax = DlgRef::PrintDoubleValue( (*it).max, aPrecision );
510 aGroupName = aTypePrefix + "_" + aMin + "_" + aMax;
511 GEOMBase::PublishSubObject( aGroup, aGroupName );
513 // this is needed just to avoid error message
514 objects.push_back(aGroup._retn());
520 SUIT_MessageBox::information( this, tr( "INF_INFO" ), tr( "GEOM_MSG_GROUPS_CREATED" ).arg( nbGroups ) );
525 //=================================================================================
526 // function : clickOnHelp()
527 // purpose : called when Help button was clicked
528 //=================================================================================
529 void MeasureGUI_ShapeStatisticsDlg::clickOnHelp()
531 GeometryGUI* aGeomGUI = dynamic_cast<GeometryGUI*>( myApp->module( "Geometry" ) );
532 myApp->onHelpContextModule( aGeomGUI ? myApp->moduleName( aGeomGUI->moduleName() ) : QString(""), "shape_statistics_operation_page.html" );