]> SALOME platform Git repositories - modules/hydro.git/blob - src/HYDROData/HYDROData_StreamAltitude.cxx
Salome HOME
Bug #388: fix coefficients for calculation of the average altitude value.
[modules/hydro.git] / src / HYDROData / HYDROData_StreamAltitude.cxx
1
2 #include "HYDROData_StreamAltitude.h"
3
4 #include "HYDROData_Document.h"
5 #include "HYDROData_Profile.h"
6 #include "HYDROData_Stream.h"
7 #include "HYDROData_ShapesTool.h"
8 #include <HYDROData_Tool.h>
9 #include <BRep_Tool.hxx>
10
11 #include <BRepBuilderAPI_MakeEdge.hxx>
12 #include <BRepBuilderAPI_MakeFace.hxx>
13 #include <BRepBuilderAPI_MakeWire.hxx>
14
15 #include <Extrema_ExtElC.hxx>
16
17 #include <GeomAPI_ProjectPointOnCurve.hxx>
18
19 #include <gp_Lin.hxx>
20
21 #include <Precision.hxx>
22
23 #include <TopExp_Explorer.hxx>
24
25 #include <TopoDS.hxx>
26 #include <TopoDS_Wire.hxx>
27 #include <TopoDS_Edge.hxx>
28
29 #include <TopTools_SequenceOfShape.hxx>
30
31 #include <Geom_Line.hxx>
32
33 #include <QStringList>
34
35 #ifdef DEB_CLASS2D
36 #include <BRepTools.hxx>
37 #include <BRep_Builder.hxx>
38 #include <BRepBuilderAPI_MakeVertex.hxx>
39 #endif
40 IMPLEMENT_STANDARD_HANDLE(HYDROData_StreamAltitude, HYDROData_IAltitudeObject)
41 IMPLEMENT_STANDARD_RTTIEXT(HYDROData_StreamAltitude, HYDROData_IAltitudeObject)
42
43 HYDROData_StreamAltitude::HYDROData_StreamAltitude()
44 : HYDROData_IAltitudeObject()
45 {
46 }
47
48 HYDROData_StreamAltitude::~HYDROData_StreamAltitude()
49 {
50 }
51
52 Standard_Real getAltitudeFromProfile( const Handle(HYDROData_Profile)& theProfile,
53                                       const Standard_Real&             theLeftDist,
54                                       const Standard_Real&             theRightDist )
55 {
56   Standard_Real aResAlt = 0.0;
57
58   gp_XY aFirstPoint, aLastPoint;
59   if ( !theProfile->GetLeftPoint( aFirstPoint ) ||
60        !theProfile->GetRightPoint( aLastPoint ) )
61     return aResAlt;
62
63   gp_Pnt aPnt1( aFirstPoint.X(), aFirstPoint.Y(), 0 );
64   gp_Pnt aPnt2( aLastPoint.X(),  aLastPoint.Y(),  0 );
65
66   Standard_Real aProfileDist = aPnt1.Distance( aPnt2 );
67
68   Standard_Real aCoeff = aProfileDist / ( theLeftDist + theRightDist );
69
70   gp_Pnt anIntPoint( aPnt1.XYZ() + ( aCoeff * theLeftDist ) * gp_Dir( gp_Vec( aPnt1, aPnt2 ) ).XYZ() );
71
72   gp_Lin aPointLine( anIntPoint, gp::DZ() );
73
74   gp_Pnt aPrevPoint;
75   gp_Lin aPrevNormal;
76   HYDROData_Profile::ProfilePoints aProfilePoints = theProfile->GetProfilePoints();
77   for ( int i = 1, n = aProfilePoints.Length(); i <= n; ++i )
78   {
79     gp_Pnt aProfPoint( aProfilePoints.Value( i ) );
80
81     Standard_Real aDist = aPointLine.Distance( aProfPoint );
82     if ( aDist <= gp::Resolution() )
83     {
84       // We found the intersected point
85       aResAlt = aProfPoint.Z();
86       break;
87     }
88    
89     gp_Lin aNormal = aPointLine.Normal( aProfPoint );
90     if ( i == 1 )
91     {
92       aPrevNormal = aNormal;
93       aPrevPoint = aProfPoint;
94       continue;
95     }
96
97     if ( aPrevNormal.Direction().Dot( aNormal.Direction() ) < 0 )
98     {
99       // We found the intersected edge
100       gp_Lin anEdgeLine( aPrevPoint, gp_Dir( gp_Vec( aPrevPoint, aProfPoint ) ) );
101      
102       Extrema_ExtElC anExtrema( aPointLine, anEdgeLine, Precision::Angular() );
103       if ( !anExtrema.IsParallel() )
104       {
105         Extrema_POnCurv aFirstPnt, aSecPnt;
106         anExtrema.Points( 1, aFirstPnt, aSecPnt );
107
108         const gp_Pnt& anIntPnt = aSecPnt.Value();
109         aResAlt = anIntPnt.Z();
110
111         break;
112       }
113     }
114
115     aPrevNormal = aNormal;
116     aPrevPoint = aProfPoint;
117   }
118
119   return aResAlt;
120 }
121
122 bool HYDROData_StreamAltitude::getBoundaryProfilesForPoint(
123   const gp_XY&               thePoint,
124   Handle(HYDROData_Profile)& theLeftProfile,
125   Handle(HYDROData_Profile)& theRightProfile ) const
126 {
127   Handle(HYDROData_Stream) aStream =
128     Handle(HYDROData_Stream)::DownCast( GetFatherObject() );
129   if ( aStream.IsNull() )
130     return false;
131
132   HYDROData_SequenceOfObjects aStreamProfiles = aStream->GetProfiles();
133   if ( aStreamProfiles.Length() < 2 )
134     return false;
135
136   Handle(HYDROData_Profile) aPrevProfile;
137   gp_Pnt aPrevPnt1, aPrevPnt2;
138   for ( int i = 1, n = aStreamProfiles.Length(); i <= n; ++i )
139   {
140     Handle(HYDROData_Profile) aProfile =
141       Handle(HYDROData_Profile)::DownCast( aStreamProfiles.Value( i ) );
142     if ( aProfile.IsNull() )
143       continue;
144
145     gp_XY aFirstPoint, aLastPoint;
146     if ( !aProfile->GetLeftPoint( aFirstPoint ) || !aProfile->GetRightPoint( aLastPoint ) )
147       continue;
148
149     gp_Pnt aPnt1( aFirstPoint.X(), aFirstPoint.Y(), 0 );
150     gp_Pnt aPnt2( aLastPoint.X(),  aLastPoint.Y(),  0 );
151
152     if ( !aPrevProfile.IsNull() )
153     {
154       BRepBuilderAPI_MakeEdge aLeftMakeEdge( aPrevPnt1, aPrevPnt2 );
155       BRepBuilderAPI_MakeEdge aBotMakeEdge( aPrevPnt2, aPnt2 );
156       BRepBuilderAPI_MakeEdge aRightMakeEdge( aPnt2, aPnt1 );
157       BRepBuilderAPI_MakeEdge aTopMakeEdge( aPnt1, aPrevPnt1 );
158
159       BRepBuilderAPI_MakeWire aMakeWire( aLeftMakeEdge.Edge(), aBotMakeEdge.Edge(), 
160                                          aRightMakeEdge.Edge(), aTopMakeEdge.Edge() );
161
162       BRepBuilderAPI_MakeFace aMakeFace( aMakeWire.Wire() );
163         
164       TopoDS_Face aProfilesFace = aMakeFace.Face();
165 #ifdef DEB_CLASS2D
166           TopoDS_Compound aCmp;
167       BRep_Builder aBB;
168       aBB.MakeCompound(aCmp);
169           aBB.Add(aCmp, aProfilesFace);
170           gp_Pnt aPnt (thePoint.X(), thePoint.Y(), 0.);
171           BRepBuilderAPI_MakeVertex aMk(aPnt);
172           aBB.Add(aCmp, aMk.Vertex());
173           BRepTools::Write(aCmp, "ProfileFace.brep");
174 #endif     
175
176           TopAbs_State aPointState =  HYDROData_Tool::ComputePointState(thePoint, aProfilesFace);
177
178 #ifdef DEB_CLASS2D
179           cout << "Point status is = " << aPointState <<endl;
180 #endif
181       if ( aPointState != TopAbs_OUT )
182       {
183         theLeftProfile = aPrevProfile;
184         theRightProfile = aProfile;
185         break;
186       }
187     }
188
189     aPrevProfile = aProfile;
190     aPrevPnt1 = aPnt1;
191     aPrevPnt2 = aPnt2;
192   }
193
194   return !theLeftProfile.IsNull() && !theRightProfile.IsNull();
195 }
196
197 double HYDROData_StreamAltitude::GetAltitudeForPoint( const gp_XY& thePoint ) const
198 {
199   double aResAltitude = GetInvalidAltitude();
200
201   Handle(HYDROData_Stream) aStream =
202     Handle(HYDROData_Stream)::DownCast( GetFatherObject() );
203   if ( aStream.IsNull() )
204     return aResAltitude;
205
206   TopoDS_Shape aStreamShape = aStream->GetTopShape();
207   if ( aStreamShape.IsNull() )
208     return aResAltitude;
209
210   TopExp_Explorer aStreamFaceExp( aStreamShape, TopAbs_FACE );
211   if ( !aStreamFaceExp.More() )
212     return aResAltitude;
213
214   // Get only face because of 2d profile wires is in compound
215   TopoDS_Face aStreamFace = TopoDS::Face( aStreamFaceExp.Current() );
216
217   // Check if point is inside of stream presentation
218   TopAbs_State aPointState = HYDROData_Tool::ComputePointState(thePoint, aStreamFace);
219
220 #ifdef DEB_CLASS2D
221       cout << "Point status is = " << aPointState <<endl;
222           TopoDS_Compound aCmp;
223       BRep_Builder aBB;
224       aBB.MakeCompound(aCmp);
225           aBB.Add(aCmp, aStreamFace);
226           gp_Pnt aPnt (thePoint.X(), thePoint.Y(), 0.);
227           BRepBuilderAPI_MakeVertex aMk(aPnt);
228           aBB.Add(aCmp, aMk.Vertex());
229           BRepTools::Write(aCmp, "FCL2d.brep");
230 #endif
231   if ( aPointState == TopAbs_OUT )
232     return aResAltitude;
233
234   // Find the two profiles between which the point is lies
235   Handle(HYDROData_Profile) aLeftProfile, aRightProfile;
236   if ( !getBoundaryProfilesForPoint( thePoint, aLeftProfile, aRightProfile ) )
237     return aResAltitude;
238
239   // Find the projections of point to borders of stream
240   gp_XYZ aPointToTest( thePoint.X(), thePoint.Y(), 0.0 );
241
242   TopoDS_Edge aStreamLeftEdge = TopoDS::Edge( aStream->GetLeftShape() );
243   TopoDS_Edge aStreamRightEdge = TopoDS::Edge( aStream->GetRightShape() );
244
245   Standard_Real aFirst = 0.0, aLast = 0.0;
246   Handle(Geom_Curve) anEdgeLeftCurve = BRep_Tool::Curve( aStreamLeftEdge, aFirst, aLast );
247   Handle(Geom_Curve) anEdgeRightCurve = BRep_Tool::Curve( aStreamRightEdge, aFirst, aLast );
248
249   GeomAPI_ProjectPointOnCurve aLeftProject( aPointToTest, anEdgeLeftCurve );
250   GeomAPI_ProjectPointOnCurve aRightProject( aPointToTest, anEdgeRightCurve );
251
252   Standard_Real aLeftDist = aLeftProject.LowerDistance();
253   Standard_Real aRightDist = aRightProject.LowerDistance();
254
255   // Find the altitude in profiles
256   Standard_Real aLeftAlt = getAltitudeFromProfile( aLeftProfile, aLeftDist, aRightDist );
257   Standard_Real aRightAlt = getAltitudeFromProfile( aRightProfile, aLeftDist, aRightDist );
258
259   // Interpolate altitudes
260   // Left profile line ( the segment between the firts and the last profile point )
261   HYDROData_Profile::ProfilePoints aLeftProfilePoints = aLeftProfile->GetProfilePoints();
262   gp_Pnt aLeftProfileP1( aLeftProfilePoints.First() );
263   aLeftProfileP1.SetZ( 0 );
264   gp_Pnt aLeftProfileP2( aLeftProfilePoints.Last() );
265   aLeftProfileP2.SetZ( 0 );
266   gp_Vec aLeftProfileVec( aLeftProfileP1, aLeftProfileP2 );
267   Handle(Geom_Line) aLeftProfileLine = new Geom_Line( gp_Ax1( aLeftProfileP1, aLeftProfileVec ) );
268   // Right profile line
269   HYDROData_Profile::ProfilePoints aRightProfilePoints = aRightProfile->GetProfilePoints();
270   gp_Pnt aRightProfileP1( aRightProfilePoints.First() );
271   aRightProfileP1.SetZ( 0 );
272   gp_Pnt aRightProfileP2( aRightProfilePoints.Last() );
273   aRightProfileP2.SetZ( 0 );
274   gp_Vec aRightProfileVec( aRightProfileP1, aRightProfileP2 );
275   Handle(Geom_Line) aRightProfileLine = new Geom_Line( gp_Ax1( aRightProfileP1, aRightProfileVec ) );
276   // The point projections on the left and right profiles
277   GeomAPI_ProjectPointOnCurve aLeftProfileProject( aPointToTest, aLeftProfileLine );
278   GeomAPI_ProjectPointOnCurve aRightProfileProject( aPointToTest, aRightProfileLine );
279   // The point distance to the left and right profiles
280   Standard_Real aLeftProfileDist = aLeftProfileProject.LowerDistance();
281   Standard_Real aRightProfileDist = aRightProfileProject.LowerDistance();
282   // The coefficients
283   Standard_Real aFirstCoeff = aLeftProfileDist / ( aLeftProfileDist + aRightProfileDist );
284   Standard_Real aSecCoeff = aRightProfileDist / ( aLeftProfileDist + aRightProfileDist );
285
286   aResAltitude = aLeftAlt * ( 1 - aFirstCoeff ) + aRightAlt * ( 1 - aSecCoeff );
287
288   return aResAltitude;
289 }
290
291
292
293