Salome HOME
1a7b515f8aad49d45d430ceae576761e43a9a4dd
[modules/hydro.git] / src / HYDROData / HYDROData_ChannelAltitude.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 "HYDROData_ChannelAltitude.h"
20
21 #include "HYDROData_Document.h"
22 #include "HYDROData_Object.h"
23 #include "HYDROData_Channel.h"
24 #include "HYDROData_Projection.h"
25 #include "HYDROData_Polyline3D.h"
26 #include "HYDROData_Profile.h"
27
28 #define _DEVDEBUG_
29 #include "HYDRO_trace.hxx"
30 #include <QString>
31
32 #include <BRepBuilderAPI_MakeVertex.hxx>
33 #include <BRepExtrema_DistShapeShape.hxx>
34
35 #include <Precision.hxx>
36 #include <TopAbs.hxx>
37 #include <TopExp.hxx>
38 #include <TopoDS.hxx>
39 #include <TopoDS_Shape.hxx>
40 #include <TopoDS_Edge.hxx>
41 #include <TopoDS_Face.hxx>
42 #include <TopoDS_Vertex.hxx>
43 #include <TopoDS_Wire.hxx>
44 #include <TopExp_Explorer.hxx>
45 #include <TopAbs_ShapeEnum.hxx>
46 #include <BRep_Tool.hxx>
47 #include <BRepTools.hxx>
48 #include <Geom_Curve.hxx>
49
50 #include <gp_Trsf.hxx>
51 #include <gp_Pnt.hxx>
52 #include <gp_Vec.hxx>
53
54 IMPLEMENT_STANDARD_HANDLE(HYDROData_ChannelAltitude, HYDROData_IAltitudeObject)
55 IMPLEMENT_STANDARD_RTTIEXT(HYDROData_ChannelAltitude, HYDROData_IAltitudeObject)
56
57 HYDROData_ChannelAltitude::HYDROData_ChannelAltitude()
58 : HYDROData_IAltitudeObject()
59 {
60 }
61
62 HYDROData_ChannelAltitude::~HYDROData_ChannelAltitude()
63 {
64 }
65
66 double HYDROData_ChannelAltitude::GetAltitudeForPoint( const gp_XY& thePoint ) const
67 {
68   DEBTRACE("HYDROData_ChannelAltitude::GetAltitudeForPoint");
69   double aResAltitude = GetInvalidAltitude();
70
71   Handle(HYDROData_Channel) aChannel =
72   Handle(HYDROData_Channel)::DownCast(GetFatherObject());
73   if (aChannel.IsNull())
74     {
75       DEBTRACE("aChannel.IsNull()");
76       return aResAltitude;
77     }
78   DEBTRACE("aChannel: " << aChannel->GetName().toStdString());
79   Handle(HYDROData_Polyline3D) aGuideLine = aChannel->GetGuideLine();
80   if (aGuideLine.IsNull())
81     {
82       DEBTRACE("aGuideLine.IsNull()");
83       return aResAltitude;
84     }
85   DEBTRACE("aGuideLine: " << aGuideLine->GetName().toStdString());
86   Handle (HYDROData_Profile) aProfile = aChannel->GetProfile();
87   if (aProfile.IsNull())
88     {
89       return aResAltitude;
90     }
91   DEBTRACE("aProfile: " << aProfile->GetName().toStdString());
92
93   // --- See GEOMImpl_ProjectionDriver.cxx
94
95   TopoDS_Shape aShape = aGuideLine->GetShape3D();
96   double middleZ = -9999;
97   aGuideLine->GetMiddleZ(middleZ); // use the middle Z value of the 3d line to help the projection.
98   gp_Pnt P1(thePoint.X(), thePoint.Y(), middleZ);
99   if (middleZ < -9000)
100     {
101       DEBTRACE("the middle Z value of the 3d line is incorrect");
102     }
103   TopoDS_Shape aPoint = BRepBuilderAPI_MakeVertex(P1).Shape();
104
105   if (aPoint.IsNull() || aShape.IsNull())
106     {
107       DEBTRACE("aPoint.IsNull() || aShape.IsNull()");
108       return aResAltitude;
109     }
110
111   if (aShape.ShapeType() != TopAbs_EDGE && aShape.ShapeType() != TopAbs_WIRE)
112     {
113       DEBTRACE("Projection aborted : the shape is neither an edge nor a wire");
114       return aResAltitude;
115     }
116
117   // Perform projection.
118   BRepExtrema_DistShapeShape aDistShSh(aPoint, aShape, Extrema_ExtFlag_MIN);
119
120   if (aDistShSh.IsDone() == Standard_False)
121     {
122       DEBTRACE("Projection not done");
123       return aResAltitude;
124     }
125
126   Standard_Boolean hasValidSolution = Standard_False;
127   Standard_Integer aNbSolutions = aDistShSh.NbSolution();
128   Standard_Integer i;
129   double aParam = 0.;
130   Standard_Real aTolConf = BRep_Tool::Tolerance(TopoDS::Vertex(aPoint));
131   Standard_Real aTolAng = 1.e-4;
132
133   for (i = 1; i <= aNbSolutions; i++)
134     {
135       Standard_Boolean isValid = Standard_False;
136       BRepExtrema_SupportType aSupportType = aDistShSh.SupportTypeShape2(i);
137       TopoDS_Shape aSupportShape = aDistShSh.SupportOnShape2(i);
138
139       if (aSupportType == BRepExtrema_IsOnEdge)
140         {
141           // Minimal distance inside edge is really a projection.
142           isValid = Standard_True;
143           aDistShSh.ParOnEdgeS2(i, aParam);
144         }
145       else if (aSupportType == BRepExtrema_IsVertex)
146         {
147           TopExp_Explorer anExp(aShape, TopAbs_EDGE);
148
149           if (aDistShSh.Value() <= aTolConf)
150             {
151               // The point lies on the shape. This means this point
152               // is really a projection.
153               for (; anExp.More() && !isValid; anExp.Next())
154                 {
155                   TopoDS_Edge aCurEdge = TopoDS::Edge(anExp.Current());
156
157                   if (aCurEdge.IsNull() == Standard_False)
158                     {
159                       TopoDS_Vertex aVtx[2];
160
161                       TopExp::Vertices(aCurEdge, aVtx[0], aVtx[1]);
162
163                       for (int j = 0; j < 2; j++)
164                         {
165                           if (aSupportShape.IsSame(aVtx[j]))
166                             {
167                               // The current edge is a projection edge.
168                               isValid = Standard_True;
169                               aSupportShape = aCurEdge;
170                               aParam = BRep_Tool::Parameter(aVtx[j], aCurEdge);
171                               break;
172                             }
173                         }
174                     }
175                 }
176             }
177           else
178             {
179               // Minimal distance to vertex is not always a real projection.
180               gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aPoint));
181               gp_Pnt aPrjPnt = BRep_Tool::Pnt(TopoDS::Vertex(aSupportShape));
182               gp_Vec aDProjP(aPrjPnt, aPnt);
183
184               for (; anExp.More() && !isValid; anExp.Next())
185                 {
186                   TopoDS_Edge aCurEdge = TopoDS::Edge(anExp.Current());
187
188                   if (aCurEdge.IsNull() == Standard_False)
189                     {
190                       TopoDS_Vertex aVtx[2];
191
192                       TopExp::Vertices(aCurEdge, aVtx[0], aVtx[1]);
193
194                       for (int j = 0; j < 2; j++)
195                         {
196                           if (aSupportShape.IsSame(aVtx[j]))
197                             {
198                               // Check if the point is a projection to the current edge.
199                               Standard_Real anEdgePars[2];
200                               Handle(Geom_Curve) aCurve = BRep_Tool::Curve(aCurEdge, anEdgePars[0], anEdgePars[1]);
201                               gp_Pnt aVal;
202                               gp_Vec aD1;
203
204                               aParam = BRep_Tool::Parameter(aVtx[j], aCurEdge);
205                               aCurve->D1(aParam, aVal, aD1);
206
207                               if (Abs(aD1.Dot(aDProjP)) <= aTolAng)
208                                 {
209                                   // The current edge is a projection edge.
210                                   isValid = Standard_True;
211                                   aSupportShape = aCurEdge;
212                                   break;
213                                 }
214                             }
215                         }
216                     }
217                 }
218             }
219         }
220
221       if (isValid)
222         {
223           if (hasValidSolution)
224             {
225               DEBTRACE("Projection aborted : multiple solutions");
226               return aResAltitude;
227             }
228
229           // Store the valid solution.
230           hasValidSolution = Standard_True;
231
232           // Normalize parameter.
233           TopoDS_Edge aSupportEdge = TopoDS::Edge(aSupportShape);
234           Standard_Real aF, aL;
235
236           BRep_Tool::Range(aSupportEdge, aF, aL);
237
238           if (Abs(aL - aF) <= aTolConf)
239             {
240               DEBTRACE("Projection aborted : degenerated projection edge");
241               return aResAltitude;
242             }
243
244           // Construct a projection vertex.
245           const gp_Pnt &aPntProj = aDistShSh.PointOnShape2(i);
246           TopoDS_Shape aProj = BRepBuilderAPI_MakeVertex(aPntProj).Shape();
247           DEBTRACE("projection: (" << aPntProj.X() << ", " << aPntProj.Y() << ", " << aPntProj.Z() << ")");
248           return aPntProj.Z() + 2.;
249         }
250     }
251
252   if (!hasValidSolution)
253     {
254       DEBTRACE("Projection aborted : no projection");
255       return aResAltitude;
256     }
257
258   return aResAltitude;
259 }
260
261
262
263