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.
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.
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
16 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 #include "HYDROData_ChannelAltitude.h"
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_PolylineXY.h"
27 #include "HYDROData_ProfileUZ.h"
28 #include "HYDROData_Profile.h"
29 #include <TDataStd_Integer.hxx>
32 #include "HYDRO_trace.hxx"
35 #include <BRepBuilderAPI_MakeVertex.hxx>
36 #include <BRepExtrema_DistShapeShape.hxx>
38 #include <Precision.hxx>
42 #include <TopoDS_Shape.hxx>
43 #include <TopoDS_Edge.hxx>
44 #include <TopoDS_Face.hxx>
45 #include <TopoDS_Vertex.hxx>
46 #include <TopoDS_Wire.hxx>
47 #include <TopExp_Explorer.hxx>
48 #include <TopAbs_ShapeEnum.hxx>
49 #include <BRep_Tool.hxx>
50 #include <BRepTools.hxx>
51 #include <Geom_Curve.hxx>
53 #include <gp_Trsf.hxx>
57 IMPLEMENT_STANDARD_RTTIEXT(HYDROData_ChannelAltitude, HYDROData_IAltitudeObject)
59 HYDROData_ChannelAltitude::HYDROData_ChannelAltitude()
60 : HYDROData_IAltitudeObject()
64 HYDROData_ChannelAltitude::~HYDROData_ChannelAltitude()
68 double HYDROData_ChannelAltitude::GetAltitudeForPoint( const gp_XY& thePoint,
71 DEBTRACE("GetAltitudeForPoint p(" << thePoint.X() << ", " << thePoint.Y() << ")");
72 double aResAltitude = GetInvalidAltitude();
74 Handle(HYDROData_Channel) aChannel =
75 Handle(HYDROData_Channel)::DownCast(GetFatherObject());
76 if (aChannel.IsNull())
78 DEBTRACE("aChannel.IsNull()");
81 DEBTRACE("aChannel: " << aChannel->GetName().toStdString());
83 Handle(HYDROData_Polyline3D) aGuideLine = aChannel->GetGuideLine();
84 if (aGuideLine.IsNull())
86 DEBTRACE("aGuideLine.IsNull()");
89 //DEBTRACE("aGuideLine: " << aGuideLine->GetName().toStdString());
91 Handle(HYDROData_PolylineXY) aGuideXY = aGuideLine->GetPolylineXY();
92 if (aGuideXY.IsNull())
94 DEBTRACE("aGuideXY.IsNull()");
97 //DEBTRACE("aGuideXY: " << aGuideXY->GetName().toStdString());
99 Handle(HYDROData_ProfileUZ) aGuideUZ = aGuideLine->GetProfileUZ();
100 if (aGuideUZ.IsNull())
102 aGuideUZ = aGuideLine->GetChildProfileUZ(); // profile obtained from bathymetry
104 if (aGuideUZ.IsNull())
106 DEBTRACE("aGuideUZ.IsNull()");
109 //DEBTRACE("aGuideUZ: " << aGuideUZ->GetName().toStdString());
111 Handle (HYDROData_Profile) aProfile = aChannel->GetProfile();
112 if (aProfile.IsNull())
116 //DEBTRACE("aProfile: " << aProfile->GetName().toStdString());
118 // --- See GEOMImpl_ProjectionDriver.cxx
121 aProfile->GetLeftPoint(LP);
122 aProfile->GetRightPoint(RP);
124 TopoDS_Shape aShape = aGuideXY->GetShape();
125 gp_Pnt P1(thePoint.X(), thePoint.Y(), 0);
126 TopoDS_Shape aPoint = BRepBuilderAPI_MakeVertex(P1).Shape();
128 if (aPoint.IsNull() || aShape.IsNull())
130 DEBTRACE("aPoint.IsNull() || aShape.IsNull()");
134 if (aShape.ShapeType() != TopAbs_EDGE && aShape.ShapeType() != TopAbs_WIRE)
136 DEBTRACE("Projection aborted : the shape is neither an edge nor a wire");
140 // Perform projection.
141 BRepExtrema_DistShapeShape aDistShSh(aPoint, aShape, Extrema_ExtFlag_MIN);
143 if (aDistShSh.IsDone() == Standard_False)
145 DEBTRACE("Projection not done");
149 Standard_Boolean hasValidSolution = Standard_False;
150 Standard_Integer aNbSolutions = aDistShSh.NbSolution();
153 Standard_Real aTolConf = BRep_Tool::Tolerance(TopoDS::Vertex(aPoint));
154 Standard_Real aTolAng = 1.e-4;
156 for (i = 1; i <= aNbSolutions; i++)
158 Standard_Boolean isValid = Standard_False;
159 BRepExtrema_SupportType aSupportType = aDistShSh.SupportTypeShape2(i);
160 TopoDS_Shape aSupportShape = aDistShSh.SupportOnShape2(i);
162 if (aSupportType == BRepExtrema_IsOnEdge)
164 // Minimal distance inside edge is really a projection.
165 isValid = Standard_True;
166 aDistShSh.ParOnEdgeS2(i, aParam);
168 else if (aSupportType == BRepExtrema_IsVertex)
170 TopExp_Explorer anExp(aShape, TopAbs_EDGE);
172 if (aDistShSh.Value() <= aTolConf)
174 // The point lies on the shape. This means this point
175 // is really a projection.
176 for (; anExp.More() && !isValid; anExp.Next())
178 TopoDS_Edge aCurEdge = TopoDS::Edge(anExp.Current());
180 if (aCurEdge.IsNull() == Standard_False)
182 TopoDS_Vertex aVtx[2];
184 TopExp::Vertices(aCurEdge, aVtx[0], aVtx[1]);
186 for (int j = 0; j < 2; j++)
188 if (aSupportShape.IsSame(aVtx[j]))
190 // The current edge is a projection edge.
191 isValid = Standard_True;
192 aSupportShape = aCurEdge;
193 aParam = BRep_Tool::Parameter(aVtx[j], aCurEdge);
202 // Minimal distance to vertex is not always a real projection.
203 gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aPoint));
204 gp_Pnt aPrjPnt = BRep_Tool::Pnt(TopoDS::Vertex(aSupportShape));
205 gp_Vec aDProjP(aPrjPnt, aPnt);
207 for (; anExp.More() && !isValid; anExp.Next())
209 TopoDS_Edge aCurEdge = TopoDS::Edge(anExp.Current());
211 if (aCurEdge.IsNull() == Standard_False)
213 TopoDS_Vertex aVtx[2];
215 TopExp::Vertices(aCurEdge, aVtx[0], aVtx[1]);
217 for (int j = 0; j < 2; j++)
219 if (aSupportShape.IsSame(aVtx[j]))
221 // Check if the point is a projection to the current edge.
222 Standard_Real anEdgePars[2];
223 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(aCurEdge, anEdgePars[0], anEdgePars[1]);
227 aParam = BRep_Tool::Parameter(aVtx[j], aCurEdge);
228 aCurve->D1(aParam, aVal, aD1);
230 if (Abs(aD1.Dot(aDProjP)) <= aTolAng)
232 // The current edge is a projection edge.
233 isValid = Standard_True;
234 aSupportShape = aCurEdge;
246 if (hasValidSolution)
248 DEBTRACE("Projection aborted : multiple solutions");
252 // Store the valid solution.
253 hasValidSolution = Standard_True;
255 // profile altitude at projection point
256 HYDROData_IPolyline::PointsList aProfilePoints = aGuideUZ->GetPoints();
257 if ( aProfilePoints.IsEmpty() )
259 DEBTRACE("empty profile UZ");
262 double aDepth = HYDROData_ProfileUZ::GetDepthFromDistance( aProfilePoints, aParam );
263 DEBTRACE("profile altitude: " << aDepth);
265 // Compute edge index.
266 TopExp_Explorer anExp(aShape, TopAbs_EDGE);
268 for (; anExp.More(); anExp.Next(), anIndex++)
270 if (aSupportShape.IsSame(anExp.Current()))
276 // get the XY distance from point to guideline
277 const gp_Pnt &aPntProj = aDistShSh.PointOnShape2(i);
278 DEBTRACE("projection: (" << aPntProj.X() << ", " << aPntProj.Y() << ", " << aPntProj.Z() << ")");
279 gp_XY aProjXY = gp_XY(aPntProj.X(), aPntProj.Y());
280 aProjXY.Subtract(thePoint);
281 double distance = aProjXY.Modulus();
283 gp_Vec2d aProjDir = aProjXY;
284 gp_Vec2d aProfileDir(LP, RP);
286 if( aProfileDir.Dot(aProjDir) < 0 )
290 DEBTRACE("distance to guideline " << distance);
292 if (GetInvertDirection())
295 // get delta altitude on section (supposed symmetric) from guideline distance (aParam)
301 HYDROData_ProfileUZ::PointsList aSectionPoints = aProfile->GetParametricPoints();
302 for ( int i = 1, aNbPoints = aSectionPoints.Size(); i <= aNbPoints; ++i )
304 const HYDROData_IPolyline::Point& aPolylinePoint = aSectionPoints.Value( i );
305 DEBTRACE(" i, size, profile point: " << i << " " << aSectionPoints.Size() << " " << aPolylinePoint.X() << " " << aPolylinePoint.Y());
306 if (aPolylinePoint.X() < distance)
309 pt1 = aPolylinePoint;
311 if (aPolylinePoint.X() >= distance)
314 pt2 = aPolylinePoint;
318 if ((i1 == 0) && (i2 == 0))
320 DEBTRACE("Projection aborted : non centered profile");
323 else if (i1 == 0) // distance < - profile width
325 DEBTRACE("distance < - profile width");
328 else if (i1 == aSectionPoints.Size()) // distance >= profile width
330 DEBTRACE("distance >= profile width");
335 delta = pt1.Y() + (pt2.Y() - pt1.Y())*(distance -pt1.X())/(pt2.X()-pt1.X());
337 aResAltitude = delta + aDepth;
338 DEBTRACE("distance XY: "<< aParam << " distance to guideline: " << distance << " final altitude: " << aResAltitude << " delta: " << delta);
343 if (!hasValidSolution)
345 DEBTRACE("Projection aborted : no projection");
353 void HYDROData_ChannelAltitude::SetInvertDirection(bool IsInverted)
355 if ( GetInvertDirection() == IsInverted )
358 TDataStd_Integer::Set( myLab.FindChild( DataTag_InvertDirection ), (Standard_Integer)IsInverted );
361 bool HYDROData_ChannelAltitude::GetInvertDirection() const
365 TDF_Label aLabel = myLab.FindChild( DataTag_InvertDirection, false );
366 if ( !aLabel.IsNull() )
368 Handle(TDataStd_Integer) anIntVal;
369 if ( aLabel.FindAttribute( TDataStd_Integer::GetID(), anIntVal ) )
370 aRes = (bool)anIntVal->Get();