Salome HOME
A fix for a refs #266 - Point insertion in a polyline with type spline
[modules/hydro.git] / src / HYDROCurveCreator / CurveCreator_Utils.cxx
1 // Copyright (C) 2013  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
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.
7 //
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.
12 //
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
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "CurveCreator_Utils.h"
21 #include "CurveCreator.hxx"
22 #include "CurveCreator_UtilsICurve.hxx"
23
24 #include <GEOMUtils.hxx>
25
26 #include <gp_Pln.hxx>
27
28 #include <TopoDS.hxx>
29 #include <TopoDS_Vertex.hxx>
30 #include <TopoDS_Wire.hxx>
31 #include <TopoDS_Edge.hxx>
32 #include <TopoDS_Compound.hxx>
33
34 #include <AIS_ListOfInteractive.hxx>
35 #include <AIS_ListIteratorOfListOfInteractive.hxx>
36 #include <AIS_Shape.hxx>
37 #include <AIS_Line.hxx>
38 #include <AIS_Trihedron.hxx>
39 #include <AIS_LocalContext.hxx>
40
41 #include <Geom_Point.hxx>
42 #include <Geom_BSplineCurve.hxx>
43 #include <Geom_Line.hxx>
44
45 #include <TopExp.hxx>
46 #include <TopExp_Explorer.hxx>
47 #include <GeomAPI_ProjectPointOnCurve.hxx>
48 #include <SelectMgr_EntityOwner.hxx>
49 #include <SelectMgr_Selection.hxx>
50 #include <Select3D_SensitivePoint.hxx>
51
52 #include <BRep_Tool.hxx>
53 #include <BRep_Builder.hxx>
54 #include <BRepBuilderAPI_MakeVertex.hxx>
55 #include <BRepBuilderAPI_MakeEdge.hxx>
56 #include <BRepBuilderAPI_MakeWire.hxx>
57
58 #include <TColgp_HArray1OfPnt.hxx>
59 #include <TColStd_HArray1OfBoolean.hxx>
60 #include <TColgp_Array1OfVec.hxx>
61 #include <GeomAPI_Interpolate.hxx>
62
63 #include <ProjLib.hxx>
64 #include <ElSLib.hxx>
65
66 #include <math.h>
67
68 #include "CurveCreator_ICurve.hxx"
69
70 const double LOCAL_SELECTION_TOLERANCE = 0.0001;
71 const int    SCENE_PIXEL_PROJECTION_TOLERANCE = 10;
72 const int    SCENE_PIXEL_POINT_TOLERANCE = 5;
73
74 //=======================================================================
75 // function : ConvertClickToPoint()
76 // purpose  : Returns the point clicked in 3D view
77 //=======================================================================
78 void CurveCreator_Utils::ConvertPointToClick( const gp_Pnt& thePoint,
79                                               Handle(V3d_View) theView,
80                                               int& x, int& y )
81 {
82   theView->Convert(thePoint.X(), thePoint.Y(), thePoint.Z(), x, y );
83 }
84
85
86 //=======================================================================
87 // function : ConvertClickToPoint()
88 // purpose  : Returns the point clicked in 3D view
89 //=======================================================================
90 gp_Pnt CurveCreator_Utils::ConvertClickToPoint( int x, int y, Handle(V3d_View) aView )
91 {
92   return GEOMUtils::ConvertClickToPoint( x, y, aView );
93 }
94
95 void CurveCreator_Utils::constructShape( const CurveCreator_ICurve* theCurve,
96                                          TopoDS_Shape& theShape )
97 {
98   BRep_Builder aBuilder;
99   TopoDS_Compound aComp;
100   aBuilder.MakeCompound( aComp );
101   for( int iSection = 0 ; iSection < theCurve->getNbSections() ; iSection++ )
102   {
103     int theISection = iSection;
104
105     CurveCreator::SectionType aSectType = theCurve->getSectionType( theISection );
106     int aPointSize = theCurve->getNbPoints( theISection );
107     if ( aPointSize == 0 )
108       continue;
109
110     bool aSectIsClosed = theCurve->isClosed( theISection );
111     bool isPolyline = aSectType == CurveCreator::Polyline;
112
113     int iPoint = 0;
114     gp_Pnt aPrevPoint, aPoint;
115     // filters the curve points to skip equal points
116     std::vector<gp_Pnt> aPoints;
117     CurveCreator_UtilsICurve::getPoint( theCurve, theISection, iPoint, aPoint );
118     aPoints.push_back( aPoint );
119     aPrevPoint = aPoint;
120     iPoint++;
121     for( ; iPoint < aPointSize; iPoint++ ) {
122       CurveCreator_UtilsICurve::getPoint( theCurve, theISection, iPoint, aPoint );
123       if ( !isEqualPoints( aPrevPoint, aPoint ) )
124         aPoints.push_back( aPoint );
125       aPrevPoint = aPoint;
126     }
127     int aNbPoints = aPoints.size();
128
129     if ( aNbPoints == 1 ) {
130       aPoint = aPoints.front();
131       TopoDS_Vertex aVertex = BRepBuilderAPI_MakeVertex( aPoint ).Vertex();
132       aBuilder.Add( aComp, aVertex );
133     }
134     else if ( aNbPoints > 1 ) {
135       Handle(TColgp_HArray1OfPnt) aHCurvePoints = new TColgp_HArray1OfPnt(1, aNbPoints);
136       TColgp_Array1OfVec aTangents(1, aNbPoints);
137       Handle(TColStd_HArray1OfBoolean) aTangentFlags = new TColStd_HArray1OfBoolean(1, aNbPoints);
138       gp_Vec aNullVec(0, 0, 0);
139
140       TopoDS_Edge aPointEdge;
141       TopoDS_Vertex aVertex;
142
143       std::vector<gp_Pnt>::const_iterator aPointIt = aPoints.begin(), aPointLast = aPoints.end();
144       aPoint = *aPointIt;
145
146       int aHIndex = 1;
147       aVertex = BRepBuilderAPI_MakeVertex( aPoint ).Vertex();
148       aBuilder.Add( aComp, aVertex );
149       if ( !isPolyline ) {
150         aHCurvePoints->SetValue( aHIndex, aPoint );
151         aTangents.SetValue( aHIndex, aNullVec );
152         aTangentFlags->SetValue( aHIndex, Standard_False );
153         aHIndex++;
154       }
155
156       aPrevPoint = aPoint;
157       aPointIt++;
158       for( ; aPointIt != aPointLast; aPointIt++ ) {
159         aPoint = *aPointIt;
160         aVertex = BRepBuilderAPI_MakeVertex( aPoint ).Vertex();
161         aBuilder.Add( aComp, aVertex );
162         if ( isPolyline ) {
163           TopoDS_Edge aPointEdge = BRepBuilderAPI_MakeEdge( aPrevPoint, aPoint ).Edge();
164           aBuilder.Add( aComp, aPointEdge );
165         }
166         else {
167           aHCurvePoints->SetValue( aHIndex, aPoint );
168           aTangents.SetValue( aHIndex, aNullVec );
169           aTangentFlags->SetValue( aHIndex, Standard_False );
170           aHIndex++;
171         }
172         aPrevPoint = aPoint;
173       }
174       if( aSectIsClosed && ( aNbPoints > 2 ) ) {
175         aPoint = aPoints.front();
176         aVertex = BRepBuilderAPI_MakeVertex( aPoint ).Vertex();
177         aBuilder.Add( aComp, aVertex );
178         if ( isPolyline ) {
179           aPointEdge = BRepBuilderAPI_MakeEdge( aPrevPoint, aPoint ).Edge();
180           aBuilder.Add( aComp, aPointEdge );
181         }
182       }
183       if( !isPolyline ) {
184         // compute BSpline
185         Handle(Geom_BSplineCurve) aBSplineCurve;
186         GeomAPI_Interpolate aGBC(aHCurvePoints, aSectIsClosed, gp::Resolution());
187         aGBC.Load(aTangents, aTangentFlags);
188
189         aGBC.Perform();
190         if ( aGBC.IsDone() )
191           aBSplineCurve = aGBC.Curve();
192         TopoDS_Edge anEdge = BRepBuilderAPI_MakeEdge( aBSplineCurve ).Edge();
193         TopoDS_Wire aWire = BRepBuilderAPI_MakeWire( anEdge ).Wire();
194         aBuilder.Add( aComp, aWire );
195       }
196     }
197   }
198   theShape = aComp;
199 }
200
201 class CompareSectionToPoint
202 {
203 public:
204   CompareSectionToPoint( const int theISection = -1, const int theIPoint = -1 )
205     : mySectionId( theISection ), myPointId( theIPoint ) {};
206   ~CompareSectionToPoint() {}
207
208   bool operator < ( const CompareSectionToPoint& theOther ) const
209   {
210     bool isLess = mySectionId < theOther.mySectionId;
211     if ( !isLess && mySectionId == theOther.mySectionId )
212       isLess = myPointId < theOther.myPointId;
213     return isLess;
214   }
215
216 private:
217   int mySectionId;
218   int myPointId;
219 };
220
221
222 void CurveCreator_Utils::getSelectedPoints( Handle(AIS_InteractiveContext) theContext,
223                                             const CurveCreator_ICurve* theCurve,
224                                             CurveCreator_ICurve::SectionToPointList& thePoints )
225 {
226   thePoints.clear();
227
228   std::list<float> aSelectedPoints;
229   gp_Pnt aPnt;
230   std::map<CompareSectionToPoint, int> aPointsMap;
231
232   CurveCreator_ICurve::SectionToPointList aPoints;
233   for ( theContext->InitSelected(); theContext->MoreSelected(); theContext->NextSelected() ) {
234     TopoDS_Vertex aVertex;
235     TopoDS_Shape aShape = theContext->SelectedShape();
236     if ( !aShape.IsNull() && aShape.ShapeType() == TopAbs_VERTEX )
237       aVertex = TopoDS::Vertex( theContext->SelectedShape() );
238
239     if ( aVertex.IsNull() )
240       continue;
241     aPnt = BRep_Tool::Pnt( aVertex );
242
243     CurveCreator_UtilsICurve::findSectionsToPoints( theCurve, aPnt.X(), aPnt.Y(), aPoints );
244     CurveCreator_ICurve::SectionToPointList::const_iterator anIt = aPoints.begin(),
245                                                             aLast = aPoints.end();
246     CompareSectionToPoint aPoint;
247     for ( ; anIt != aLast; anIt++ ) {
248       aPoint = CompareSectionToPoint( (*anIt).first, (*anIt).second );
249       if ( aPointsMap.find( aPoint ) != aPointsMap.end() )
250         continue;
251       aPointsMap[aPoint] = 0;
252
253       thePoints.push_back( *anIt );
254     }
255   }
256 }
257
258 void CurveCreator_Utils::setSelectedPoints( Handle(AIS_InteractiveContext) theContext,
259                                             const CurveCreator_ICurve* theCurve,
260                                             const CurveCreator_ICurve::SectionToPointList& thePoints )
261 {
262   if ( !theCurve )
263     return;
264
265   Handle(AIS_InteractiveObject) anAIS = theCurve->getAISObject();
266   if ( anAIS.IsNull() )
267     return;
268   Handle(AIS_Shape) anAISShape = Handle(AIS_Shape)::DownCast( anAIS );
269   if ( anAISShape.IsNull() )
270     return;
271
272   //ASL: we convert list of point indices to list of points coordinates
273   int aSize = thePoints.size();
274   std::vector<gp_Pnt> aPntsToSelect( aSize );
275
276   CurveCreator_ICurve::SectionToPointList::const_iterator
277                      aPIt = thePoints.begin(), aPLast = thePoints.end();
278   CurveCreator_ICurve::SectionToPoint aSToPoint;
279   for( int i=0; aPIt != aPLast; aPIt++, i++ )
280   {
281     gp_Pnt aPntToSelect;
282     CurveCreator_UtilsICurve::getPoint( theCurve, aPIt->first, aPIt->second, aPntToSelect );
283     aPntsToSelect[i] = aPntToSelect;
284   }
285
286   theContext->ClearSelected( Standard_False );
287   //ASL: we switch off automatic highlight to improve performance of selection
288   theContext->SetAutomaticHilight( Standard_False );
289
290   Handle_SelectMgr_Selection aSelection = anAISShape->Selection( AIS_Shape::SelectionMode( TopAbs_VERTEX ) );
291   for( aSelection->Init(); aSelection->More(); aSelection->Next() )
292   {
293     Handle_SelectBasics_SensitiveEntity aSenEntity = aSelection->Sensitive();
294     Handle_Select3D_SensitivePoint aSenPnt = Handle_Select3D_SensitivePoint::DownCast( aSenEntity );
295
296     gp_Pnt anOwnerPnt = aSenPnt->Point();
297     Handle_SelectMgr_EntityOwner anOwner = Handle_SelectMgr_EntityOwner::DownCast( aSenPnt->OwnerId() );
298
299
300     CurveCreator_ICurve::SectionToPointList::const_iterator anIt = thePoints.begin(),
301                                                                    aLast = thePoints.end();
302     bool isFound = false;
303     for( int i=0; i<aSize; i++ )
304     {
305       bool isIntersect = fabs( aPntsToSelect[i].X() - anOwnerPnt.X() ) < LOCAL_SELECTION_TOLERANCE &&
306                          fabs( aPntsToSelect[i].Y() - anOwnerPnt.Y() ) < LOCAL_SELECTION_TOLERANCE;
307       if( isIntersect )
308       {
309         theContext->AddOrRemoveSelected( anOwner, Standard_False );
310         break;
311       }
312     }
313   }
314
315   //ASL: we switch on again automatic highlight (otherwise selection will not be shown)
316   //     and call HilightPicked to draw selected owners
317   theContext->SetAutomaticHilight( Standard_True );
318   theContext->LocalContext()->HilightPicked( Standard_True );
319 }
320
321 //=======================================================================
322 // function : setLocalPointContext
323 // purpose  : Open/close the viewer local context
324 //=======================================================================
325 void CurveCreator_Utils::setLocalPointContext( const CurveCreator_ICurve* theCurve,
326                                                Handle(AIS_InteractiveContext) theContext,
327                                                const bool theOpen )
328 {
329   if ( !theContext )
330     return;
331
332   if ( theOpen ) {
333     // Open local context if there is no one
334     if ( !theContext->HasOpenedContext() ) {
335       theContext->ClearCurrents( false );
336       theContext->OpenLocalContext( false/*use displayed objects*/, true/*allow shape decomposition*/ );
337     }
338     // load the curve AIS object to the local context with the point selection
339     Handle(AIS_InteractiveObject) anAIS = theCurve->getAISObject();
340     if ( !anAIS.IsNull() )
341     {
342       if ( anAIS->IsKind( STANDARD_TYPE( AIS_Shape ) ) )
343       {
344         theContext->Load( anAIS, -1/*selection mode*/, true/*allow decomposition*/ );
345         theContext->Activate( anAIS, AIS_Shape::SelectionMode( (TopAbs_ShapeEnum)TopAbs_VERTEX ) );
346       }
347     }
348   }
349   else {
350     if ( theContext->HasOpenedContext() )
351       theContext->CloseAllContexts();
352   }
353 }
354
355 bool CurveCreator_Utils::pointOnObject( Handle(V3d_View) theView,
356                                         Handle(AIS_InteractiveObject) theObject,
357                                         const int theX, const int theY,
358                                         gp_Pnt& thePoint,
359                                         gp_Pnt& thePoint1, gp_Pnt& thePoint2 )
360 {
361   bool isFullFound = false;
362
363   if ( theObject.IsNull() || theView.IsNull() )
364     return isFullFound;
365   Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast( theObject );
366   if ( aShape.IsNull() )
367     return isFullFound;
368   const TopoDS_Compound& aCompound = TopoDS::Compound( aShape->Shape() );
369   if ( aCompound.IsNull() )
370     return isFullFound;
371
372   gp_Pnt aCurPoint, aCurPoint1, aCurPoint2;
373   gp_Pnt aFoundPoint, aFoundPnt1, aFoundPnt2;
374   Standard_Real aParameter;
375   bool isFound = false;
376   int aDelta, aMinDelta = 2*SCENE_PIXEL_PROJECTION_TOLERANCE*SCENE_PIXEL_PROJECTION_TOLERANCE;
377   TopExp_Explorer anExp( aCompound, TopAbs_EDGE );
378   for ( ; anExp.More(); anExp.Next())
379   {
380     const TopoDS_Edge& anEdge = TopoDS::Edge(anExp.Current());
381     if ( anEdge.IsNull() )
382       continue;
383     Standard_Real aFirst, aLast;
384     Handle(Geom_Curve) aCurve = BRep_Tool::Curve( anEdge, aFirst, aLast );
385     if ( aCurve->IsKind( STANDARD_TYPE(Geom_BSplineCurve) ) ) {
386       Handle(Geom_BSplineCurve) aBSplineCurve =
387                           Handle(Geom_BSplineCurve)::DownCast( aCurve );
388       if ( !aBSplineCurve.IsNull() ) {
389         isFound = hasProjectPointOnCurve( theView, theX, theY, aBSplineCurve,
390                                           aParameter, aDelta );
391         if ( isFound ) {
392           aCurPoint = aBSplineCurve->Value( aParameter );
393           Standard_Integer anI1, anI2;
394           aBSplineCurve->LocateU( aParameter, LOCAL_SELECTION_TOLERANCE, anI1, anI2 );
395           aCurPoint1 = aBSplineCurve->Value( aBSplineCurve->Knot( anI1 ) );
396           aCurPoint2 = aBSplineCurve->Value( aBSplineCurve->Knot( anI2 ) );
397         }
398       }
399     }
400     else { // a curve built on a polyline edge
401       Handle(Geom_Line) aGLine = Handle(Geom_Line)::DownCast( aCurve );
402       if ( aGLine.IsNull() )
403         continue;
404       isFound = hasProjectPointOnCurve( theView, theX, theY, aGLine, aParameter,
405                                         aDelta );
406       if ( isFound ) {
407         aCurPoint = aGLine->Value( aParameter );
408         TopoDS_Vertex V1, V2;
409         TopExp::Vertices( anEdge, V1, V2, Standard_True );
410         if ( V1.IsNull() || V2.IsNull() )
411           continue;
412         aCurPoint1 = BRep_Tool::Pnt(V1);
413         aCurPoint2 = BRep_Tool::Pnt(V2);
414
415         // check that the projected point is on the bounded curve
416         gp_Vec aVec1( aCurPoint1, aCurPoint );
417         gp_Vec aVec2( aCurPoint2, aCurPoint );
418         isFound = fabs( aVec1.Angle( aVec2 ) - M_PI ) < LOCAL_SELECTION_TOLERANCE;
419       }
420     }
421     if ( isFound && aMinDelta >= aDelta ) {
422       aMinDelta = aDelta;
423
424       isFullFound = true;
425       aFoundPnt1 = aCurPoint1;
426       aFoundPnt2 = aCurPoint2;
427       aFoundPoint = aCurPoint;
428     }
429   }
430   if ( isFullFound ) {
431     int aX, anY, aX1, anY1, aX2, anY2;
432     int aDelta;
433     CurveCreator_Utils::ConvertPointToClick( aFoundPoint, theView, aX, anY );
434     CurveCreator_Utils::ConvertPointToClick( aFoundPnt1, theView, aX1, anY1 );
435     CurveCreator_Utils::ConvertPointToClick( aFoundPnt2, theView, aX2, anY2 );
436
437     isFullFound = !isEqualPixels( aX, anY, aX1, anY1, SCENE_PIXEL_POINT_TOLERANCE, aDelta ) &&
438                   !isEqualPixels( aX, anY, aX2, anY2, SCENE_PIXEL_POINT_TOLERANCE, aDelta );
439     if ( isFullFound ) {
440       thePoint = aFoundPoint;
441       thePoint1 = aFoundPnt1;
442       thePoint2 = aFoundPnt2;
443     }
444   }
445   return isFullFound;
446 }
447
448 bool CurveCreator_Utils::hasProjectPointOnCurve( Handle(V3d_View) theView,
449                                                  const int theX, const int theY,
450                                                  const Handle(Geom_Curve)& theCurve,
451                                                  Standard_Real& theParameter,
452                                                  int& theDelta )
453 {
454   bool isFound = false;
455   if ( theView.IsNull() )
456     return isFound;
457
458   gp_Pnt aPoint = CurveCreator_Utils::ConvertClickToPoint( theX, theY, theView );
459
460   GeomAPI_ProjectPointOnCurve aProj( aPoint, theCurve );
461   Standard_Integer aNbPoint = aProj.NbPoints();
462   if (aNbPoint > 0) {
463     for (Standard_Integer j = 1; j <= aNbPoint && !isFound; j++) {
464       gp_Pnt aNewPoint = aProj.Point( j );
465       theParameter = aProj.Parameter( j );
466
467       int aX, anY;
468       CurveCreator_Utils::ConvertPointToClick( aNewPoint, theView, aX, anY );
469
470       isFound = isEqualPixels( aX, anY, theX, theY, SCENE_PIXEL_PROJECTION_TOLERANCE, theDelta );
471     }
472   }
473   return isFound;
474 }
475
476 bool CurveCreator_Utils::isEqualPixels( const int theX, const int theY, const int theOtherX,
477                                         const int theOtherY, const double theTolerance, int& theDelta )
478 {
479   int aXDelta = abs( theX - theOtherX );
480   int anYDelta = abs( theY - theOtherY );
481
482   theDelta = aXDelta*aXDelta + anYDelta*anYDelta;
483
484   return aXDelta < theTolerance && anYDelta < theTolerance;
485 }
486
487 bool CurveCreator_Utils::isEqualPoints( const gp_Pnt& thePoint, const gp_Pnt& theOtherPoint )
488 {
489   return theOtherPoint.IsEqual( thePoint, LOCAL_SELECTION_TOLERANCE );
490 }