]> SALOME platform Git repositories - modules/hydro.git/blob - src/HYDROGUI/HYDROGUI_MeasurementToolOp.cxx
Salome HOME
Merge branch 'BR_H2018_2' of https://codev-tuleap.cea.fr/plugins/git/salome/hydro...
[modules/hydro.git] / src / HYDROGUI / HYDROGUI_MeasurementToolOp.cxx
1 // Copyright (C) 2014-2015  EDF-R&D
2 // This library is free software; you can redistribute it and/or
3 // modify it under the terms of the GNU Lesser General Public
4 // License as published by the Free Software Foundation; either
5 // version 2.1 of the License, or (at your option) any later version.
6 //
7 // This library is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10 // Lesser General Public License for more details.
11 //
12 // You should have received a copy of the GNU Lesser General Public
13 // License along with this library; if not, write to the Free Software
14 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
15 //
16 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
17 //
18
19 #include "HYDROGUI_MeasurementToolOp.h"
20
21 #include "HYDROGUI_DataModel.h"
22 #include "HYDROGUI_Module.h"
23
24 #include <HYDROData_Object.h>
25 #include <HYDROData_IPolyline.h>
26
27 #include <LightApp_Application.h>
28
29 #include <SUIT_Desktop.h>
30 #include <HYDROGUI_Tool2.h>
31 #include <HYDROGUI_MeasurementToolDlg.h>
32 #include <OCCViewer_ViewModel.h>
33 #include <OCCViewer_ViewManager.h>
34 #include <OCCViewer_ViewPort3d.h>
35 #include <OCCViewer_ViewWindow.h>
36 #include <BRep_Builder.hxx>
37 #include <BRepBuilderAPI_MakeVertex.hxx>
38 #include <TopoDS_Vertex.hxx>
39 #include <TopoDS_Compound.hxx>
40 #include <AIS_Shape.hxx>
41 #include <CurveCreator_Utils.hxx>
42 #include <QMouseEvent>
43 #include <TopExp.hxx>
44 #include <HYDROData_Iterator.h>
45 #include <HYDROData_PolylineXY.h>
46 #include <GCPnts_AbscissaPoint.hxx>
47 #include <TopExp_Explorer.hxx>
48 #include <BRepAdaptor_Curve.hxx>
49 #include <TopoDS.hxx>
50 #include <vector>
51 #include <utility>
52 #include <Prs3d_Drawer.hxx>
53 #include <BRepAlgo.hxx>
54 #include <BRepAdaptor_Curve.hxx>
55 #include <BRepLib_MakeEdge.hxx>
56 #include <GeomAPI_ProjectPointOnCurve.hxx>
57 #include <BRepLib_MakePolygon.hxx>
58
59
60 HYDROGUI_MeasurementToolOp::HYDROGUI_MeasurementToolOp( HYDROGUI_Module* theModule )
61   : HYDROGUI_Operation( theModule ),
62   myMeasDlg(0),
63   myLineMaker(NULL),
64   myAISLineM(NULL),
65   myDist(0),
66  // myFAd(NULL),
67   myFu(0)
68 {
69   setName( tr( "MEASUREMENT_TOOL" ) );
70 }
71
72 HYDROGUI_MeasurementToolOp::~HYDROGUI_MeasurementToolOp()
73 {
74   if (myLineMaker)
75     delete myLineMaker;
76 }
77
78 void HYDROGUI_MeasurementToolOp::startOperation()
79 {
80   HYDROGUI_Operation::startOperation();
81
82   myMeasDlg = new HYDROGUI_MeasurementToolDlg( module()->getApp()->desktop() );
83   myMeasDlg->setModal( false );
84   myMeasDlg->setWindowTitle(getName());
85   myMeasDlg->show(); 
86
87   //Tool: draw a distance line
88   LightApp_Application* anApp = module()->getApp();
89   OCCViewer_ViewManager* aViewManager =
90     dynamic_cast<OCCViewer_ViewManager*>( anApp->getViewManager( OCCViewer_Viewer::Type(), true ) );
91
92   setPreviewManager( aViewManager );
93
94   connect( myMeasDlg, SIGNAL( clearLine() ), this, SLOT( onClearLine() ) );
95
96   connect( myMeasDlg, SIGNAL( doExit() ), this, SLOT( onExit() ) );
97
98   OCCViewer_Viewer* aViewer = aViewManager->getOCCViewer();
99
100   disconnect(aViewManager, SIGNAL(mousePress(SUIT_ViewWindow*, QMouseEvent*)), 
101     aViewer, SLOT(onMousePress(SUIT_ViewWindow*, QMouseEvent*)));
102   connect(aViewManager, SIGNAL(mousePress(SUIT_ViewWindow*, QMouseEvent*)), 
103     this, SLOT(onMousePress(SUIT_ViewWindow*, QMouseEvent*)));
104
105   //polyline names
106   HYDROData_Iterator anIter( doc(), KIND_POLYLINEXY );
107   QStringList aPolylineNames;
108   myPolyObjs.clear();
109   for ( ; anIter.More(); anIter.Next() )
110   {
111     Handle(HYDROData_PolylineXY) aPolylineObj = Handle(HYDROData_PolylineXY)::DownCast( anIter.Current() );
112     myPolyObjs.push_back(aPolylineObj);
113     aPolylineNames << aPolylineObj->GetName();
114   }
115   myMeasDlg->setPolylineNames(aPolylineNames);
116 }
117
118 void HYDROGUI_MeasurementToolOp::onClearLine()
119 {
120   eraseLine();
121   myDist = 0;
122   //myPolyObjs.clear();
123   myMeasDlg->setTotalDst(0);
124   delete myLineMaker;
125   myLineMaker = NULL;
126   myFW = TopoDS_Wire();
127 }
128
129 void HYDROGUI_MeasurementToolOp::onMousePress(SUIT_ViewWindow* theWindow, QMouseEvent* theEvent)
130 {
131   OCCViewer_ViewManager* aViewManager = getPreviewManager();
132   if ( !aViewManager )
133     return;
134
135   OCCViewer_ViewWindow* aViewWindow = (OCCViewer_ViewWindow*)aViewManager->getActiveView();
136   if ( !aViewWindow )
137     return;
138
139   OCCViewer_ViewPort3d* aViewPort = aViewWindow->getViewPort();
140   if ( !aViewPort )
141     return;
142
143   Handle(V3d_View) aView = aViewPort->getView();
144   if ( aView.IsNull() )
145     return;
146
147   OCCViewer_Viewer* aViewer = aViewManager->getOCCViewer();
148   if ( !aViewer )
149     return;
150
151   Handle(AIS_InteractiveContext) aCtx = aViewer->getAISContext();
152   if ( aCtx.IsNull() )
153     return;  
154
155   gp_Pnt aPnt = CurveCreator_Utils::ConvertClickToPoint( theEvent->x(), theEvent->y(), aView );
156
157   TopoDS_Shape aRes;
158
159   if (myMeasDlg->IsLDChecked())
160   {
161     if (!myLineMaker)
162     {
163       myLineMaker = new BRepLib_MakePolygon();
164       myLineMaker->Add(aPnt);
165       aRes = myLineMaker->FirstVertex(); 
166     }
167     else
168     {   
169       myLineMaker->Add(aPnt);
170       aRes = myLineMaker->Shape();
171       const TopoDS_Edge& aLE = myLineMaker->Edge();
172       TopoDS_Vertex aFV = TopExp::FirstVertex(aLE, true);
173       TopoDS_Vertex aLV = TopExp::LastVertex(aLE, true);
174       double aNDist = BRep_Tool::Pnt(aFV).Distance(BRep_Tool::Pnt(aLV));
175       myDist += aNDist;
176       myMeasDlg->setTotalDst(QString::number(myDist));
177     }
178
179     if ( !myAISLineM.IsNull() )
180     {
181       if ( aCtx->HasOpenedContext() )
182         aCtx->CloseLocalContext();
183       aCtx->Erase( myAISLineM, Standard_False );
184     }
185   }
186   else
187   {
188     double prec = 70; //minimum precision
189     int selectInd = myMeasDlg->currentSelectedPolyline();
190     if (selectInd == -1)
191       return;
192     Handle(HYDROData_PolylineXY) aPolylineObj = myPolyObjs[selectInd];
193     TopoDS_Shape aShape = aPolylineObj->GetShape();
194     TopExp_Explorer exp(aShape, TopAbs_WIRE);
195     double fdist_min = RealLast();
196     TopoDS_Wire minWire;
197     BRepAdaptor_Curve minC;
198     double minU;
199     for (;exp.More(); exp.Next())
200     {
201       TopoDS_Wire W = TopoDS::Wire(exp.Current());
202       if (W.IsNull())
203         continue;
204       TopExp_Explorer expW(W, TopAbs_EDGE);
205       if (!expW.More())
206         continue;      
207       TopoDS_Edge E = TopoDS::Edge(expW.Current());
208       expW.Next();
209       if (expW.More())
210         E = BRepAlgo::ConcatenateWireC0(W);
211       BRepAdaptor_Curve Ad(E);
212       Handle(Geom_BSplineCurve) aBsp = Ad.Curve().BSpline();
213       std::vector<double> params;
214       double Fp = Ad.FirstParameter();
215       double Lp = Ad.LastParameter();
216       params.push_back(Fp);
217       params.push_back(Lp);
218       if (!aBsp.IsNull())
219       {
220         TColStd_Array1OfReal aKnots = aBsp->Knots();
221         for (int i = 1; i <= aKnots.Size(); i++)
222         {
223           if (aKnots(i) > Fp && aKnots(i) < Lp)
224             params.push_back(aKnots(i));
225         }
226       }
227       //in some cases, extrema gives inaccurate result -> 
228       //split bspline by knot params and try to find minimum distance
229       //on each interval
230       std::sort(params.begin(), params.end());
231       for (int i = 0; i < params.size() - 1; i++ )
232       {
233         //Extrema_ExtPC extrema(aPnt, Ad, params[i], params[i+1]);
234         GeomAPI_ProjectPointOnCurve aProj; //extrema wrapper
235         aProj.Init (aPnt, Ad.Curve().Curve(), params[i], params[i+1]);
236         if (aProj.NbPoints() > 0)
237         {
238           double fdist = aProj.LowerDistance();
239           gp_Pnt aFP = aProj.NearestPoint();
240           int x1=-1, y1=-1, x2=-1, y2=-1;
241           CurveCreator_Utils::ConvertPointToClick(aPnt, aView, x1, y1);
242           CurveCreator_Utils::ConvertPointToClick(aFP, aView, x2, y2);
243           gp_Pnt2d pp1((double)x1, (double)y1);
244           gp_Pnt2d pp2((double)x2, (double)y2);
245           int aWinSX, aWinSY;
246           aView->Window()->Size(aWinSX, aWinSY);
247           double pd = pp1.Distance(pp2);
248           double WinDiagDist = sqrt ((double)aWinSX*(double)aWinSX + (double)aWinSY*(double)aWinSY);
249           if (fdist <= prec || pd / WinDiagDist < 0.08)
250           {
251             if (fdist < fdist_min) 
252             {
253               fdist_min = fdist;           
254               minWire = W;
255               minU = aProj.LowerDistanceParameter();
256               minC.Initialize(E);
257             }
258           }
259         }
260       }
261     }
262     //
263     if (!minWire.IsNull())
264     {
265       if (myFW.IsNull())
266       {
267         myFu = minU;
268         myFW = minWire;
269         aRes = BRepLib_MakeVertex(aPnt);
270       }
271       else
272       {
273         if (myFW.IsSame(minWire))
274         {
275           //calc distance on current curve 
276           double LenAlongCurv = GCPnts_AbscissaPoint::Length(minC, myFu, minU);          
277           myFW = TopoDS_Wire();
278           if (!BRep_Tool::IsClosed(minWire))
279           {
280             aRes = BRepLib_MakeEdge(minC.Curve().Curve(), Min(myFu, minU), Max (myFu, minU));
281             myMeasDlg->setTotalDst(QString::number(LenAlongCurv));
282           }
283           else
284           {
285             double Len2 = GCPnts_AbscissaPoint::Length(minC) - LenAlongCurv;
286             if (LenAlongCurv < Len2)
287               aRes = BRepLib_MakeEdge(minC.Curve().Curve(), Min(myFu, minU), Max (myFu, minU));
288             else
289             {
290               TopoDS_Compound aCmpEd;
291               BRep_Builder aB;
292               aB.MakeCompound(aCmpEd);
293               aB.Add(aCmpEd, BRepLib_MakeEdge(minC.Curve().Curve(), minC.FirstParameter(), Min(myFu, minU)));
294               aB.Add(aCmpEd, BRepLib_MakeEdge(minC.Curve().Curve(), Max(myFu, minU), minC.LastParameter()));
295               aRes = aCmpEd;
296             }
297             myMeasDlg->setTotalDst(QString::number(LenAlongCurv) + ", " + QString::number(Len2));
298           }
299         }
300       }
301     }
302   }
303
304   if (aRes.IsNull())
305     return;
306
307   aCtx->Erase( myAISLineM, Standard_False );
308
309   myAISLineM = new AIS_Shape( aRes );
310
311   myAISLineM->SetColor( Quantity_NOC_ORANGE );
312   //Handle(Prs3d_Drawer) aHA = myAISLineM->HilightAttributes();
313
314   myAISLineM->SetWidth( 3 );
315   //Handle(Prs3d_PointAspect) anAspect = mySplitPointPreview->Attributes()->PointAspect();
316   //anAspect->SetScale(2.0);
317   //anAspect->SetTypeOfMarker(Aspect_TOM_RING1);
318   //anAspect->SetColor(Quantity_NOC_BLACK);
319   //mySplitPointPreview->Attributes()->SetPointAspect( anAspect );
320   
321   aCtx->SetZLayer(myAISLineM, Graphic3d_ZLayerId_Topmost);
322
323   if ( aCtx->HasOpenedContext() )
324     aCtx->CloseLocalContext();
325   aCtx->Display( myAISLineM, Standard_False );  
326   aCtx->UpdateCurrentViewer();
327 }
328
329 void HYDROGUI_MeasurementToolOp::eraseLine()
330 {
331   OCCViewer_ViewManager* aViewManager = getPreviewManager();
332   if ( aViewManager )
333   {
334     if ( OCCViewer_Viewer* aViewer = aViewManager->getOCCViewer() )
335     {
336       if ( !myAISLineM.IsNull() )
337       {
338         Handle(AIS_InteractiveContext) aCtx = aViewer->getAISContext();
339         if ( !aCtx.IsNull() )
340         {
341           if ( aCtx->HasOpenedContext() )
342             aCtx->CloseLocalContext();
343           aCtx->Erase( myAISLineM, Standard_False );
344         }
345         myAISLineM.Nullify();
346         aCtx->UpdateCurrentViewer();
347       }      
348     }
349   }
350 }
351
352 void HYDROGUI_MeasurementToolOp::abortOperation()
353 {
354   if (!myMeasDlg->GetExitFlag())
355     myMeasDlg->done(0);
356 }
357
358 void HYDROGUI_MeasurementToolOp::onExit()
359 {
360   onClearLine();
361   OCCViewer_ViewManager* aViewManager = getPreviewManager();
362   OCCViewer_Viewer* aViewer = aViewManager->getOCCViewer();
363
364   if (aViewManager && aViewer)
365   {
366     disconnect(aViewManager, SIGNAL(mousePress(SUIT_ViewWindow*, QMouseEvent*)), 
367       this, SLOT(onMousePress(SUIT_ViewWindow*, QMouseEvent*)));
368
369     connect(aViewManager, SIGNAL(mousePress(SUIT_ViewWindow*, QMouseEvent*)), 
370       aViewManager->getOCCViewer(), SLOT(onMousePress(SUIT_ViewWindow*, QMouseEvent*)));
371   }
372
373   if (myLineMaker)
374     delete myLineMaker;
375
376   this->blockSignals(true);
377   HYDROGUI_Operation::abort();
378   this->blockSignals(false);
379 }
380
381
382
383
384