1 // Copyright (C) 2007-2014 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 #include "HYDROData_StreamLinearInterpolation.h"
24 #include <HYDROData_Profile.h>
25 #include <HYDROData_ProfileUZ.h>
27 #include <gp_Lin2d.hxx>
28 #include <BRepAdaptor_Curve.hxx>
29 #include <HYDROData_ShapesTool.h>
30 #include <GCPnts_UniformAbscissa.hxx>
31 #include <Geom2dAPI_InterCurveCurve.hxx>
32 #include <Geom2d_Line.hxx>
33 #include <TopoDS_Shape.hxx>
35 #include <HYDROData_Tool.h>
36 #include <GCE2d_MakeLine.hxx>
37 #include <TopoDS_Iterator.hxx>
38 #include <TopExp_Explorer.hxx>
39 #include <BRepAlgo.hxx>
40 #include <Geom2dAdaptor_Curve.hxx>
45 #include <BRepBuilderAPI_MakeEdge2d.hxx>
46 #include <BRepBuilderAPI_MakeEdge.hxx>
47 #include <BRep_Tool.hxx>
48 #include <BRepBuilderAPI_MakeWire.hxx>
49 #include <TopoDS_Face.hxx>
51 #include <BRepBuilderAPI_MakeFace.hxx>
54 #include <Geom_Plane.hxx>
55 #include <TopoDS_Wire.hxx>
56 #include <BRepLib.hxx>
57 #include <BRepLib_MakePolygon.hxx>
58 #include <TopoDS_Compound.hxx>
59 #include <BRep_Builder.hxx>
61 static std::vector<gp_Pnt2d> GetProfileUZPoints(const Handle(HYDROData_Profile)& theProfile)
63 Handle(HYDROData_ProfileUZ) aProfileUZ = theProfile->GetProfileUZ( false );
64 HYDROData_ProfileUZ::PointsList aSectPointsList = aProfileUZ->GetPoints();
65 std::vector<gp_Pnt2d> points;
66 points.reserve(aSectPointsList.Size());
67 for ( int i = 1; i <= aSectPointsList.Size(); i++ )
69 const HYDROData_ProfileUZ::Point& aSectPoint = aSectPointsList(i);
70 points.push_back( gp_Pnt2d(aSectPoint.X(), aSectPoint.Y()));
75 static void GetMaxDist(const std::vector<gp_Pnt2d>& PNTS,
83 std::vector<double> dist;
84 dist.reserve(PNTS.size()-1);
85 for (int i=0; i<PNTS.size()-1; i++)
87 //dist.push_back(PNTS[i].Distance(PNTS[i+1])); //via distance between p1/p2
88 dist.push_back(std::abs(PNTS[i].X()-PNTS[i+1].X())); //via U-diff of p1/p2
90 for (int i=0; i<dist.size(); i++)
99 for (int i=0; i<dist.size(); i++)
102 if (d > dmax2 && d < dmax)
107 static void InsertPoints(std::vector<gp_Pnt2d>& points, int nbpoints)
109 points.reserve(points.size() + nbpoints);
112 double dmax=0, dmax2=0;
114 GetMaxDist(points, dmax, dmax2, imax);
117 nbPins = floor(dmax/dmax2);
119 nbPins = nbpoints; //one segment, put all points here
120 //insert nbPins points in [imax, imax+1] segment
121 gp_Pnt2d p1 = points[imax];
122 gp_Pnt2d p2 = points[imax+1];
127 if (nbPins>nbpoints) //deny to add more points than needed
129 for (int i=0;i<nbPins;i++)
131 double t = ((double)i+1)/((double)nbPins+1);
132 double Xp = X0 + (X1-X0)*t;
133 double Yp = Y0 + (Y1-Y0)*t;
135 points.insert(points.begin() + imax + 1, P);
139 assert (nbpoints == 0);
142 static void PolyToCurve2d(const Handle(HYDROData_PolylineXY)& poly, Handle(Geom2d_Curve)& c2d)
146 TopoDS_Shape sh = poly->GetShape();
147 if (sh.ShapeType() == TopAbs_COMPOUND)
149 TopoDS_Iterator it(sh);
158 if (sh.ShapeType() == TopAbs_EDGE)
159 ee = TopoDS::Edge(sh);
160 else if (sh.ShapeType() == TopAbs_WIRE)
161 ee = BRepAlgo::ConcatenateWireC0(TopoDS::Wire(sh)); //convert to bspline
166 BRepAdaptor_Curve Ad(ee);
168 c2d = HYDROData_Tool::BRepAdaptorTo2DCurve(Ad);
171 static void InterProfilesAndHAX(const HYDROData_SequenceOfObjects& profiles,
172 const Handle(Geom2d_Curve)& Hax2d,
173 std::map<double, Handle(HYDROData_Profile)>& profToInterParam,
174 std::vector<bool>& paramToSwapFlag,
175 std::vector<std::string>* warnings)
177 for (int i=1;i<=profiles.Size();i++)
179 Handle(HYDROData_Profile) aProfile = Handle(HYDROData_Profile)::DownCast(profiles(i));
181 aProfile->GetLeftPoint( LP, false, true );
182 aProfile->GetRightPoint( RP, false, true );
183 gp_Pnt2d P1(LP), P2(RP);
184 double d = P2.Distance(P1);
185 if (d < gp::Resolution())
188 warnings->push_back(aProfile->GetName().toStdString() + " is skipped: Left and Right points is the same");
191 Handle(Geom2d_Line) lin2d = new Geom2d_Line(P1,gp_Dir2d(P2.XY()-P1.XY()));
192 gp_Dir2d prof_dir2d = lin2d->Direction();
194 Geom2dAdaptor_Curve linAd(lin2d, 0, d);
195 Geom2dAdaptor_Curve haxAd(Hax2d);
196 Geom2dInt_GInter isec( linAd, haxAd, 1.0e-6, 1.0e-6);
200 warnings->push_back(aProfile->GetName().toStdString() + " is skipped: intersection between hydraulic axis & profile is failed");
203 if (isec.NbPoints() == 0)
206 warnings->push_back(aProfile->GetName().toStdString() + " is skipped: no intersection between hydraulic axis & profile");
209 if (isec.NbPoints() > 1)
212 warnings->push_back(aProfile->GetName().toStdString() + " is skipped; intersection between hydraulic axis & profile produces more than 1 point");
215 double param = isec.Point(1).ParamOnSecond();
217 gp_Vec2d vec_on_hax_intersec;
218 haxAd.D1(param, int_p2d, vec_on_hax_intersec);
219 gp_Dir2d d_hax(vec_on_hax_intersec);
220 double ang = d_hax.Angle(prof_dir2d);
222 paramToSwapFlag.push_back(true);
224 paramToSwapFlag.push_back(false);
225 profToInterParam[param] = aProfile;
229 static bool EquidParamsOnHAX(const Handle(Geom2d_Curve)& Hax2d, double step, double fp, double lp, std::set<double>& params)
231 Geom2dAdaptor_Curve ad(Hax2d);
232 GCPnts_UniformAbscissa GUA(ad, step, fp, lp);
236 for(int i = 1; i<= GUA.NbPoints(); i++)
237 params.insert(GUA.Parameter(i));
242 static void GetPointsOnBanks(const std::vector<double>& gua_params,
243 const Handle(Geom2d_Curve)& Hax2d,
244 const Handle(Geom2d_Curve)& LB2d,
245 const Handle(Geom2d_Curve)& RB2d,
246 std::map<double, std::pair<IntRes2d_IntersectionPoint, IntRes2d_IntersectionPoint>>& parToBankPoints,
247 std::vector<std::string>* warnings,
248 const std::map<double, std::pair<Handle(HYDROData_Profile), Handle(HYDROData_Profile)>>* intermParamToProfPair)
250 for(int i = 0; i < gua_params.size(); i++)
252 double par = gua_params[i];
255 Hax2d->D1(par, p, v); //if non-diff?
256 gp_Pnt2d outpLB, outpRB;
258 gp_Dir2d n2d(v.X(), v.Y()); //ignore Z (Z==0)
260 //nLine2d is an orthogonal line to hydr. axis
261 gp_Pnt2d p2d(gp_Pnt2d(p.X(), p.Y()));
262 Handle(Geom2d_Line) nLine2d = new Geom2d_Line(p2d, n2d);
263 //intersect nLine2d with banks
264 Geom2dAPI_InterCurveCurve intL(LB2d, nLine2d);
265 Geom2dAPI_InterCurveCurve intR(RB2d, nLine2d);
267 if (warnings && intL.NbPoints()==0 )
269 std::string coord = (QString::number(p2d.X()) + ", "+QString::number(p2d.Y())).toStdString();
270 if (intermParamToProfPair && intermParamToProfPair->count(par) != 0)
272 std::string fpn = intermParamToProfPair->at(par).first->GetName().toStdString();
273 std::string spn = intermParamToProfPair->at(par).second->GetName().toStdString();
274 warnings->push_back("no intersection between intermediate profile (point on h.axis:("+
275 coord +"), located between " + fpn + " & " + spn + ") and left bank found; skipped");
278 warnings->push_back("no intersection between intermediate profile (point on h.axis:("+ coord +")) and left bank found; skipped");
281 if (warnings && intR.NbPoints()==0)
283 std::string coord = (QString::number(p2d.X()) + ", "+QString::number(p2d.Y())).toStdString();
284 if (intermParamToProfPair && intermParamToProfPair->count(par) != 0)
286 std::string fpn = intermParamToProfPair->at(par).first->GetName().toStdString();
287 std::string spn = intermParamToProfPair->at(par).second->GetName().toStdString();
288 warnings->push_back("no intersection between intermediate profile (point on h.axis:("+
289 coord +"), located between " + fpn + " & " + spn + ") and right bank found; skipped");
292 warnings->push_back("no intersection between intermediate profile (point on h.axis:("+ coord +")) and right bank found; skipped");
295 if ( intL.NbPoints()==0 || intR.NbPoints()==0)
298 IntRes2d_IntersectionPoint aNearSolL, aNearSolR;
299 double min_sq_dist = Precision::Infinite();
300 for (int j=1;j<=intL.NbPoints();j++)
302 double sq_dist = p2d.SquareDistance(intL.Point(j));
303 if (min_sq_dist > sq_dist)
305 min_sq_dist = sq_dist;
306 //aNearSolL = intL.Point(j);
307 aNearSolL = intL.Intersector().Point(j);
310 min_sq_dist = Precision::Infinite();
311 for (int j=1;j<=intR.NbPoints();j++)
313 double sq_dist = p2d.SquareDistance(intR.Point(j));
314 if (min_sq_dist > sq_dist)
316 min_sq_dist = sq_dist;
317 //aNearSolR = intR.Point(j);
318 aNearSolR = intR.Intersector().Point(j);
322 std::pair<IntRes2d_IntersectionPoint, IntRes2d_IntersectionPoint> int_pair(aNearSolL, aNearSolR);
323 parToBankPoints[par]=int_pair;
328 void BuildFace(const std::map<double, std::pair<IntRes2d_IntersectionPoint, IntRes2d_IntersectionPoint>>& parToBankPoints,
329 const Handle(Geom2d_Curve)& LB2d,
330 const Handle(Geom2d_Curve)& RB2d,
331 HYDROData_Stream::PrsDefinition& prsDef)
333 prsDef.myPrs3D.Nullify();
334 prsDef.myPrs2D.Nullify();
335 prsDef.myLeftBank.Nullify();
336 prsDef.myRightBank.Nullify();
337 prsDef.myInlet.Nullify();
338 prsDef.myOutlet.Nullify();
340 double lb_1, lb_2, rb_1, rb_2;
341 lb_1 = parToBankPoints.begin()->second.first.ParamOnFirst();
342 rb_1 = parToBankPoints.begin()->second.second.ParamOnFirst();
344 lb_2 = parToBankPoints.rbegin()->second.first.ParamOnFirst();
345 rb_2 = parToBankPoints.rbegin()->second.second.ParamOnFirst();
347 //stat = GetItersectionParam(F_prof, LB2d, lb_1) && GetItersectionParam(F_prof, RB2d, rb_1)
348 // && GetItersectionParam(S_prof, LB2d, lb_2) && GetItersectionParam(S_prof, RB2d, rb_2);
350 BRepBuilderAPI_MakeEdge2d LEM(LB2d, lb_1, lb_2);
353 BRepBuilderAPI_MakeEdge2d REM(RB2d, rb_1, rb_2);
356 TopoDS_Edge LBE = LEM.Edge();
357 TopoDS_Edge RBE = REM.Edge();
358 if (LBE.IsNull() || RBE.IsNull())
360 BRepBuilderAPI_MakeEdge PFEM(BRep_Tool::Pnt(LEM.Vertex1()), BRep_Tool::Pnt(REM.Vertex1()));
361 BRepBuilderAPI_MakeEdge PLEM(BRep_Tool::Pnt(LEM.Vertex2()), BRep_Tool::Pnt(REM.Vertex2()));
366 TopoDS_Edge FProfE = PFEM.Edge();
367 TopoDS_Edge SProfE = PLEM.Edge();
368 BRepBuilderAPI_MakeWire WM(FProfE, LBE, SProfE, RBE);
371 TopoDS_Wire W = WM.Wire();
372 BRepLib::BuildCurves3d(W);
373 BRepBuilderAPI_MakeFace FM(Geom_Plane(gp::XOY()).Pln(), WM.Wire());
376 prsDef.myPrs2D = FM.Face();
377 prsDef.myLeftBank = LBE;
378 prsDef.myRightBank = RBE;
379 prsDef.myInlet = FProfE;
380 prsDef.myOutlet = SProfE;
385 void reversePoints(std::vector<gp_Pnt2d>& points)
387 std::reverse(points.begin(), points.end());
390 void HYDROData_StreamLinearInterpolation::Perform(const HYDROData_SequenceOfObjects& profiles,
393 const Handle(HYDROData_PolylineXY)& hax,
394 const Handle(HYDROData_PolylineXY)& LB,
395 const Handle(HYDROData_PolylineXY)& RB,
396 HYDROData_Bathymetry::AltitudePoints& outBathypoints,
397 bool buildPresentationShapes,
398 bool estimateWarnOnly,
399 HYDROData_Stream::PrsDefinition& prsDef,
400 std::vector<std::string>* warnings)
402 //intersect profiles with given hydr.axis
403 if (hax.IsNull() || LB.IsNull() || RB.IsNull())
406 Handle(Geom2d_Curve) Hax2d;
407 PolyToCurve2d(hax, Hax2d);
408 if (hax->IsClosed() || Hax2d->IsClosed()) //can't be closed
411 warnings->push_back(hax->GetName().toStdString() + " is closed; abort");
415 std::map<double, Handle(HYDROData_Profile)> InterParamToProf;
416 std::vector<bool> paramToSwapFlag;
417 //profToInterParam is output param map: profile to intersection param on hydr.axis
418 InterProfilesAndHAX(profiles, Hax2d, InterParamToProf, paramToSwapFlag, warnings);
420 std::vector<std::vector<gp_Pnt2d>> profilesPoints;
421 profilesPoints.reserve(InterParamToProf.size());
424 //for (int i=1;i<=InterParamToProf.Extent();i++)
425 for( std::map<double, Handle(HYDROData_Profile)>::iterator it = InterParamToProf.begin(); it != InterParamToProf.end(); ++it )
427 //ordered by param on hydr axis
428 Handle(HYDROData_Profile) aProfile = it->second;
429 const std::vector<gp_Pnt2d>& profile_points = GetProfileUZPoints(aProfile);
430 profilesPoints.push_back(profile_points);
431 if (profile_points.size() > maxNbPoints)
432 maxNbPoints = profile_points.size();
434 std::set<double> paramsOnHAX;
436 if (InterParamToProf.size() <= 1)
439 warnings->push_back("Insufficient count of correct input profiles; abort");
443 EquidParamsOnHAX(Hax2d, stepOnHA, InterParamToProf.begin()->first,
444 InterParamToProf.rbegin()->first, paramsOnHAX);
446 //prepare ParamsPerSegm - number of interm.profiles for profile_points
447 std::vector<std::vector<double>> ParamsPerSegm;
448 std::set<double>::iterator it_params_hax = paramsOnHAX.begin();
449 std::map<double, Handle(HYDROData_Profile)>::iterator it_p = InterParamToProf.begin();
451 std::map<double, std::pair<Handle(HYDROData_Profile), Handle(HYDROData_Profile)>> intermParamToProfPair; //for warnings only
454 ParamsPerSegm.resize(profilesPoints.size()-1);
455 for( int k=0; it_p != InterParamToProf.end(); )
457 if (*it_params_hax < it_p->first)
459 double val = *it_params_hax;
460 ParamsPerSegm[k].push_back(val);
464 const Handle(HYDROData_Profile)& cp = it_p->second;
466 const Handle(HYDROData_Profile)& np = it_p->second;
467 std::pair<Handle(HYDROData_Profile), Handle(HYDROData_Profile)> profPair(cp, np);
468 intermParamToProfPair[val] = profPair;
476 ParamsPerSegm.back().push_back(*paramsOnHAX.rbegin());
478 std::map<double, std::pair<IntRes2d_IntersectionPoint, IntRes2d_IntersectionPoint>> parToBankPoints;
479 std::vector<double> paramHAXVec;
480 paramHAXVec.reserve(paramsOnHAX.size());
481 for( std::set<double>::iterator it = paramsOnHAX.begin(); it != paramsOnHAX.end(); ++it )
482 paramHAXVec.push_back(*it);
484 Handle(Geom2d_Curve) LB2d, RB2d;
485 PolyToCurve2d(LB, LB2d);
486 PolyToCurve2d(RB, RB2d);
487 GetPointsOnBanks( paramHAXVec, Hax2d, LB2d, RB2d, parToBankPoints, warnings, &intermParamToProfPair);
489 if (buildPresentationShapes)
491 //parToBankPoints.begin()->second.;
492 //double lp1 = parToBankPoints.rbegin()->first;
494 //Handle(HYDROData_Profile) F_prof = InterParamToProf.begin()->second;
495 //Handle(HYDROData_Profile) S_prof = InterParamToProf.rbegin()->second;
496 BuildFace(parToBankPoints, LB2d, RB2d, prsDef);
500 if (estimateWarnOnly)
503 maxNbPoints = Max(pointsToInsert, maxNbPoints);
505 //insert points to profiles
506 for (int i=0;i<profilesPoints.size();i++)
508 int nbPointsToInsert = maxNbPoints - profilesPoints[i].size();
509 //insert nbPointsToInsert points to current profile
510 InsertPoints(profilesPoints[i], nbPointsToInsert);
513 for (int i=0;i<profilesPoints.size();i++)
515 bool toSwap = paramToSwapFlag[i];
518 std::vector<gp_Pnt2d>& prof = profilesPoints[i];
523 TopoDS_Compound cmp2d;
524 if ( buildPresentationShapes)
526 BRep_Builder().MakeCompound(cmp2d);
527 BRep_Builder().Add(cmp2d, prsDef.myLeftBank);
528 BRep_Builder().Add(cmp2d, prsDef.myRightBank);
531 for (int i=0;i<profilesPoints.size()-1;i++)
533 const std::vector<gp_Pnt2d>& prof1 = profilesPoints[i];
534 const std::vector<gp_Pnt2d>& prof2 = profilesPoints[i+1];
535 std::vector<std::vector<gp_Pnt2d>> IntermProf;
537 std::map<int, double> indToParam; //index of im.profile to param on hax. ()
538 for (int j=0;j<ParamsPerSegm[i].size();j++)
540 double param = ParamsPerSegm[i][j];
541 if (parToBankPoints.count(param) > 0) //not intersected with banks; skip this
544 int NbIntermProf = indToParam.size();
545 IntermProf.resize(NbIntermProf);
547 for (int l=0;l<NbIntermProf;l++)
548 IntermProf[l].resize(prof1.size());
549 //calc interm. between prof1 & prof2
550 assert (prof1.size() == prof2.size());
551 for (int j=0;j<prof1.size();j++)
553 gp_Pnt2d P1 = prof1[j];
554 gp_Pnt2d P2 = prof2[j];
559 std::map<int, double>::iterator it = indToParam.begin();
560 for ( int m=0; it != indToParam.end(); it++, m++ )
563 double t = ((double)ind+1)/((double)NbIntermProf+1);
564 double Xp = X0 + (X1-X0)*t;
565 double Yp = Y0 + (Y1-Y0)*t;
567 IntermProf[m][j] = P;
570 std::map<int, double>::iterator it = indToParam.begin();
571 for ( int m=0; it != indToParam.end(); it++, m++ )
573 const std::vector<gp_Pnt2d>& im_prof = IntermProf[m];
574 double param = it->second;
575 const std::pair<IntRes2d_IntersectionPoint, IntRes2d_IntersectionPoint>& BB = parToBankPoints[param]; //param is included in map; no checks
576 gp_Pnt2d LP = BB.first.Value();
577 gp_Pnt2d RP = BB.second.Value();
578 HYDROData_ProfileUZ::PointsList pl;
579 for (int k=0;k<im_prof.size();k++)
580 pl.Append(im_prof[k].XY());
581 HYDROData_Profile::ProfilePoints profile_points3d = HYDROData_Profile::CalculateProfilePoints(pl, LP.XY(), RP.XY());
582 for (int k=1;k<=profile_points3d.Length();k++)
584 HYDROData_Bathymetry::AltitudePoint AP(profile_points3d(k).X(), profile_points3d(k).Y(), profile_points3d(k).Z());
585 outBathypoints.push_back(AP);
587 if (buildPresentationShapes)
589 if (m==0 || i == profilesPoints.size()-2 && param == indToParam.rbegin()->second) //if last prof1/prof2 segment => take a last profile too
591 BRepLib_MakePolygon PM;
592 for (int k=1;k<=profile_points3d.Length();k++)
593 PM.Add(gp_Pnt(profile_points3d(k)));
596 const TopoDS_Wire& resW = PM.Wire();
597 BRep_Builder().Add(cmp2d, resW);
603 if (buildPresentationShapes)
605 prsDef.myPrs3D = cmp2d;
607 //outBathy->SetAltitudePoints(bathypoints);