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_PolylineOperator.h>
20 #include <HYDROData_Document.h>
21 #include <BRepAdaptor_Curve.hxx>
22 #include <BRep_Builder.hxx>
23 #include <BRepBuilderAPI_MakeEdge2d.hxx>
24 #include <BRepBuilderAPI_MakeWire.hxx>
25 #include <Extrema_ExtPC.hxx>
26 #include <NCollection_Vector.hxx>
27 #include <Precision.hxx>
28 #include <ShapeAnalysis_TransferParametersProj.hxx>
29 #include <ShapeBuild_Edge.hxx>
31 #include <TopoDS_Edge.hxx>
32 #include <TopoDS_Wire.hxx>
34 #include <TopExp_Explorer.hxx>
35 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
38 template<class T> void append( std::vector<T>& theList, const std::vector<T>& theList2 )
40 int aSize = theList.size();
41 int aNewSize = aSize + theList2.size();
46 theList.resize( aNewSize );
47 for( int i=aSize, j=0; i<aNewSize; i++, j++ )
48 theList[i] = theList2[j];
51 bool HYDROData_PolylineOperator::Split( const Handle( HYDROData_Document )& theDoc,
52 const Handle( HYDROData_PolylineXY )& thePolyline,
53 const gp_Pnt2d& thePoint,
54 double theTolerance ) const
56 std::vector<gp_Pnt2d> aPointsList( 1 );
57 aPointsList[0] = thePoint;
58 std::vector<TopoDS_Wire> aCurves = GetWires( thePolyline );
60 for( int i=0, n=aCurves.size(); i<n; i++ )
62 std::vector<TopoDS_Shape> aCurvesList = Split( aCurves[i], thePoint, theTolerance );
63 bool isLocalOK = CreatePolylines( theDoc, thePolyline->GetName(), aCurvesList, true );
64 isOK = isOK && isLocalOK;
69 bool HYDROData_PolylineOperator::Split( const Handle( HYDROData_Document )& theDoc,
70 const Handle( HYDROData_PolylineXY )& thePolyline,
71 const Handle( HYDROData_PolylineXY )& theTool,
72 double theTolerance ) const
74 HYDROData_SequenceOfObjects aSeq;
75 aSeq.Append( theTool );
76 return split( theDoc, thePolyline, aSeq, theTolerance, -1 );
79 bool HYDROData_PolylineOperator::Split( const Handle( HYDROData_Document )& theDoc,
80 const HYDROData_SequenceOfObjects& thePolylines,
83 int f = thePolylines.Lower(), l = thePolylines.Upper();
84 for( int i=f; i<=l; i++ )
86 Handle( HYDROData_PolylineXY ) aPolyline = Handle( HYDROData_PolylineXY )::DownCast( thePolylines.Value( i ) );
87 if( !split( theDoc, aPolyline, thePolylines, theTolerance, i ) )
93 bool HYDROData_PolylineOperator::Merge( const Handle( HYDROData_Document )& theDoc,
94 const QString& theName,
95 const HYDROData_SequenceOfObjects& thePolylines,
96 bool isConnectByNewSegment,
99 TopoDS_Shape aMergedPolyline;
101 int f = thePolylines.Lower(), l = thePolylines.Upper();
102 for( int i=f; i<=l; i++ )
104 Handle( HYDROData_PolylineXY ) aPolyline = Handle( HYDROData_PolylineXY )::DownCast( thePolylines.Value( i ) );
105 std::vector<TopoDS_Wire> aCurves = GetWires( aPolyline );
106 for( int j=0, m=aCurves.size(); j<m; j++ )
107 if( !Merge( aMergedPolyline, aCurves[j], isConnectByNewSegment, theTolerance ) )
111 std::vector<TopoDS_Shape> aShapes( 1 );
112 aShapes[0] = aMergedPolyline;
113 CreatePolylines( theDoc, theName, aShapes, false );
118 bool HYDROData_PolylineOperator::Merge( TopoDS_Shape& theShape, const TopoDS_Wire& theWire,
119 bool isConnectByNewSegment, double theTolerance )
125 bool HYDROData_PolylineOperator::split( const Handle( HYDROData_Document )& theDoc,
126 const Handle( HYDROData_PolylineXY )& thePolyline,
127 const HYDROData_SequenceOfObjects& theTools,
129 int theIgnoreIndex ) const
131 std::vector<TopoDS_Wire> aCurves = GetWires( thePolyline );
132 std::vector<TopoDS_Wire> aToolCurves;
133 for( int i=theTools.Lower(), n=theTools.Upper(); i<=n; i++ )
134 if( i!=theIgnoreIndex )
136 Handle( HYDROData_PolylineXY ) aToolPolyline =
137 Handle( HYDROData_PolylineXY )::DownCast( theTools.Value( i ) );
138 append( aToolCurves, GetWires( aToolPolyline ) );
143 int n = aCurves.size();
144 std::vector<TopoDS_Shape> aResults( n );
145 for( int i=0; i<n; i++ )
146 aResults[i] = aCurves[i];
148 for( int j=0, m=aToolCurves.size(); j<m; j++ )
150 std::vector<TopoDS_Shape> aNewResults;
151 for( int k=0, q=aResults.size(); k<q; k++ )
153 std::vector<TopoDS_Shape> aCurvesList = Split( TopoDS::Wire( aResults[k] ), aToolCurves[j], theTolerance );
154 append( aNewResults, aCurvesList );
156 aResults = aNewResults;
159 CreatePolylines( theDoc, thePolyline->GetName(), aResults, true );
164 std::vector<TopoDS_Wire> HYDROData_PolylineOperator::GetWires( const Handle( HYDROData_PolylineXY )& thePolyline )
166 std::vector<TopoDS_Wire> aResult;
168 TopoDS_Shape aShape = thePolyline->GetShape();
170 if( aShape.ShapeType()==TopAbs_WIRE )
172 aResult.push_back( TopoDS::Wire( aShape ) );
176 TopExp_Explorer anExp( aShape, TopAbs_WIRE );
177 for( ; anExp.More(); anExp.Next() )
179 aResult.push_back( TopoDS::Wire( anExp.Current() ) );
185 static Standard_Boolean OrderCurveEdges(
186 const TopoDS_Wire& theWire,
187 NCollection_Vector<TopoDS_Edge>& theEdges,
188 Standard_Boolean& theIsClosed)
190 TopTools_IndexedDataMapOfShapeListOfShape aVertexToEdges;
191 TopExp::MapShapesAndAncestors(theWire,
192 TopAbs_VERTEX, TopAbs_EDGE, aVertexToEdges);
193 const Standard_Integer aVCount = aVertexToEdges.Extent();
196 return Standard_False;
200 Standard_Integer aEndCount = 0;
201 for (Standard_Integer aVN = 1; aVN <= aVCount; ++aVN)
203 const Standard_Integer aEdgeCount =
204 aVertexToEdges.FindFromIndex(aVN).Extent();
211 return Standard_False;
214 theIsClosed = (aEndCount == 0);
215 if (!theIsClosed && aEndCount != 2)
217 return Standard_False;
221 Standard_Integer aVN = 1;
224 while (aVN <= aVCount &&
225 aVertexToEdges.FindFromIndex(aVN).Extent() == 2)
231 TopTools_ListOfShape* aEdges = &aVertexToEdges.ChangeFromIndex(aVN);
232 while (!aEdges->IsEmpty())
234 const TopoDS_Edge aEdge = TopoDS::Edge(aEdges->First());
235 aEdges->RemoveFirst();
236 theEdges.Append(aEdge);
237 Standard_Integer aVN2 =
238 aVertexToEdges.FindIndex(TopExp::FirstVertex(aEdge));
241 aVN2 = aVertexToEdges.FindIndex(TopExp::LastVertex(aEdge));
245 aEdges = &aVertexToEdges.ChangeFromIndex(aVN2);
246 if (aEdges->First().IsEqual(aEdge))
248 aEdges->RemoveFirst();
252 const TopoDS_Edge aEdge = TopoDS::Edge(aEdges->First());
254 aEdges->Append(aEdge);
257 return (!theIsClosed && theEdges.Size() == aVCount - 1) ||
258 (theIsClosed && theEdges.Size() == aVCount);
261 static Standard_Real ProjectPointToEdge(
262 const gp_Pnt& thePoint,
263 const TopoDS_Edge& theEdge,
264 Standard_Real& theParameter)
266 BRepAdaptor_Curve aECurve(theEdge);
267 Extrema_ExtPC aAlgo(thePoint, aECurve);
268 Standard_Integer aMinEN = -2;
269 Standard_Real aMinSqDist = DBL_MAX;
272 const Standard_Integer aECount = aAlgo.NbExt();
275 for (Standard_Integer aEN = 1; aEN <= aECount; ++aEN)
277 const gp_Pnt& aP = aAlgo.Point(aEN).Value();
278 const Standard_Real aSqDist = thePoint.SquareDistance(aP);
279 if (aMinSqDist > aSqDist)
281 aMinSqDist = aSqDist;
288 const Standard_Real aParams[] =
289 {aECurve.FirstParameter(), aECurve.LastParameter()};
290 const gp_Pnt aEnds[] = {aECurve.Value(aParams[0]), aECurve.Value(aParams[1])};
291 const Standard_Real aSqDists[] =
292 {thePoint.SquareDistance(aEnds[0]), thePoint.SquareDistance(aEnds[1])};
293 for (Standard_Integer aEI = 0; aEI < 2; ++aEI)
295 if (aMinSqDist > aSqDists[aEI])
297 aMinSqDist = aSqDists[aEI];
304 theParameter = aParams[-aMinEN];
308 const Extrema_POnCurv& aPOnC = aAlgo.Point(aMinEN);
309 const gp_Pnt& aPoint = aPOnC.Value();
310 theParameter = aPOnC.Parameter();
311 for (Standard_Integer aEI = 0; aEI < 2; ++aEI)
313 if (Abs(theParameter - aParams[aEI]) < Precision::PConfusion() ||
314 aPoint.SquareDistance(aEnds[aEI]) < Precision::SquareConfusion())
316 theParameter = aParams[aEI];
322 static void SplitCurveByPoint(
323 const NCollection_Vector<TopoDS_Edge>& theEdges,
324 const Standard_Integer theEdgeIndex,
325 const Standard_Real theParameter,
326 NCollection_Vector<TopoDS_Edge>& theEdges1,
327 NCollection_Vector<TopoDS_Edge>& theEdges2)
329 for (Standard_Integer aEI = 0; aEI < theEdgeIndex; ++aEI)
331 theEdges1.Append(theEdges(aEI));
334 const TopoDS_Edge& aEdge = theEdges(theEdgeIndex);
335 BRepAdaptor_Curve aECurve(aEdge);
336 Standard_Integer aParamI = -1;
337 const Standard_Real aEdgeEndParams[] =
338 {aECurve.FirstParameter(), aECurve.LastParameter()};
339 if (Abs(theParameter - aEdgeEndParams[0]) < Precision::PConfusion())
343 else if (Abs(theParameter - aEdgeEndParams[1]) < Precision::PConfusion())
348 const TopAbs_Orientation aOrient = aEdge.Orientation();
349 if (aOrient == TopAbs_REVERSED)
354 const Standard_Integer aECount = theEdges.Size();
357 NCollection_Vector<TopoDS_Edge>* aEdges = (theEdgeIndex != 0) ? &theEdges1 : &theEdges2;
358 for (Standard_Integer aEI = theEdgeIndex; aEI < aECount; ++aEI)
360 aEdges->Append(theEdges(aEI));
363 else if (aParamI == 1)
365 theEdges1.Append(aEdge);
366 for (Standard_Integer aEI = theEdgeIndex; aEI < aECount; ++aEI)
368 theEdges2.Append(theEdges(aEI));
373 TopoDS_Edge aFE = TopoDS::Edge(aEdge.Oriented(TopAbs_FORWARD));
374 ShapeAnalysis_TransferParametersProj aSATPP(aFE, TopoDS_Face());
375 aSATPP.SetMaxTolerance(Precision::Confusion());
376 TopoDS_Vertex aSplitV;
377 BRep_Builder().MakeVertex(
378 aSplitV, aECurve.Value(theParameter), Precision::Confusion());
380 TopoDS_Edge aEParts[] = {
381 ShapeBuild_Edge().CopyReplaceVertices(aFE, TopoDS_Vertex(),
382 TopoDS::Vertex(aSplitV.Oriented(TopAbs_REVERSED))),
383 ShapeBuild_Edge().CopyReplaceVertices(aFE, aSplitV, TopoDS_Vertex())};
384 ShapeBuild_Edge().CopyPCurves(aEParts[0], aFE);
385 ShapeBuild_Edge().CopyPCurves(aEParts[1], aFE);
386 BRep_Builder().SameRange(aEParts[0], Standard_False);
387 BRep_Builder().SameRange(aEParts[1], Standard_False);
388 BRep_Builder().SameParameter(aEParts[0], Standard_False);
389 BRep_Builder().SameParameter(aEParts[1], Standard_False);
390 aSATPP.TransferRange(aEParts[0],
391 aEdgeEndParams[0], theParameter, Standard_False);
392 aSATPP.TransferRange(aEParts[1],
393 theParameter, aEdgeEndParams[1], Standard_False);
394 aEParts[0].Orientation(aOrient);
395 aEParts[1].Orientation(aOrient);
397 const Standard_Integer aFirstPI = (aOrient != TopAbs_REVERSED) ? 0 : 1;
398 theEdges1.Append(aEParts[aFirstPI]);
399 theEdges2.Append(aEParts[1 - aFirstPI]);
401 for (Standard_Integer aEI = theEdgeIndex + 1; aEI < aECount; ++aEI)
403 theEdges2.Append(theEdges(aEI));
408 static void CollectCurveWire(
409 const NCollection_Vector<TopoDS_Edge>& theEdges, TopoDS_Wire& theWire)
411 BRep_Builder aBulder;
412 aBulder.MakeWire(theWire);
413 NCollection_Vector<TopoDS_Edge>::Iterator aEIt(theEdges);
414 for (; aEIt.More(); aEIt.Next())
416 aBulder.Add(theWire, aEIt.Value());
420 static void CollectCurveWire(
421 const NCollection_Vector<TopoDS_Edge>& theEdges1,
422 const NCollection_Vector<TopoDS_Edge>& theEdges2,
423 TopoDS_Wire& theWire)
425 BRep_Builder aBulder;
426 aBulder.MakeWire(theWire);
427 const NCollection_Vector<TopoDS_Edge>* aEdges[] = {&theEdges1, &theEdges2};
428 for (Standard_Integer aEI = 0; aEI < 2; ++aEI)
430 NCollection_Vector<TopoDS_Edge>::Iterator aEIt(*aEdges[aEI]);
431 for (; aEIt.More(); aEIt.Next())
433 aBulder.Add(theWire, aEIt.Value());
438 std::vector<TopoDS_Shape> HYDROData_PolylineOperator::Split( const TopoDS_Wire& theWire,
439 const gp_Pnt2d& thePoint,
440 double theTolerance )
442 std::vector<TopoDS_Shape> aResult;
443 NCollection_Vector<TopoDS_Edge> aEdges;
444 Standard_Boolean isClosed;
445 if (!OrderCurveEdges(theWire, aEdges, isClosed))
447 aResult.push_back(theWire);
451 const gp_Pnt aP(thePoint.X(), thePoint.Y(), 0);
452 Standard_Real aMinSqDist = DBL_MAX;
454 Standard_Real aSParam;
455 for (int aECount = aEdges.Size(), aEI = 0; aEI < aECount; ++aEI)
457 Standard_Real aParam;
458 const Standard_Real aSqDist =
459 ProjectPointToEdge(aP, aEdges(aEI), aParam);
460 if (aMinSqDist > aSqDist)
462 aMinSqDist = aSqDist;
468 NCollection_Vector<TopoDS_Edge> aEdges1, aEdges2;
469 SplitCurveByPoint(aEdges, aSEI, aSParam, aEdges1, aEdges2);
473 CollectCurveWire(aEdges1, aWire);
474 if (!aEdges2.IsEmpty())
476 aResult.push_back(aWire);
477 CollectCurveWire(aEdges2, aWire);
482 CollectCurveWire(aEdges2, aEdges1, aWire);
484 aResult.push_back(aWire);
488 std::vector<TopoDS_Shape> HYDROData_PolylineOperator::Split( const TopoDS_Wire& theWire,
489 const TopoDS_Wire& theTool,
490 double theTolerance )
492 std::vector<TopoDS_Shape> aResult;
497 std::vector<TopoDS_Shape> HYDROData_PolylineOperator::Split( const std::vector<TopoDS_Wire>& theWires,
498 double theTolerance )
500 std::vector<TopoDS_Shape> aResult;
505 bool HYDROData_PolylineOperator::CreatePolylines( const Handle( HYDROData_Document )& theDoc,
506 const QString& theNamePrefix,
507 const std::vector<TopoDS_Shape>& theShapes,
510 if( theDoc.IsNull() )
513 int n = theShapes.size();
514 for( int i=0; i<n; i++ )
516 Handle( HYDROData_PolylineXY ) aPolyline =
517 Handle( HYDROData_PolylineXY )::DownCast( theDoc->CreateObject( KIND_POLYLINEXY ) );
518 if( aPolyline.IsNull() )
521 aPolyline->SetShape( theShapes[i] );