+//=======================================================================
+//function : CreatePipeWithDifferentSections
+//purpose :
+//=======================================================================
+TopoDS_Shape GEOMImpl_PipeDriver::CreatePipeWithDifferentSections
+ (const TopoDS_Wire& theWirePath,
+ const Handle(TopTools_HSequenceOfShape) theHSeqBases,
+ const Handle(TopTools_HSequenceOfShape) theHSeqLocs,
+ const Standard_Boolean theWithContact,
+ const Standard_Boolean theWithCorrect)
+{
+ TopoDS_Shape aShape;
+
+ TopoDS_Wire aWirePath = theWirePath;
+
+ Standard_Integer nbBases = theHSeqBases->Length();
+ Standard_Integer nbLocs = (theHSeqLocs.IsNull() ? 0 : theHSeqLocs->Length());
+
+ if (nbLocs && nbLocs != nbBases) {
+ Standard_ConstructionError::Raise("Number of sections is not equal to number of locations ");
+ }
+
+ TopTools_SequenceOfShape aSeqBases;
+ TopTools_SequenceOfShape aSeqLocs;
+ TopTools_SequenceOfShape aSeqFaces;
+
+ Standard_Integer i = 1;
+ for (i = 1; i <= nbBases; i++) {
+ if (theHSeqBases->Value(i).IsNull())
+ continue;
+
+ // Make copy to prevent modifying of base object 0020766 : EDF 1320
+ TopoDS_Shape aShapeBase;
+ BRepBuilderAPI_Copy Copy (theHSeqBases->Value(i));
+ if (Copy.IsDone())
+ aShapeBase = Copy.Shape();
+
+ TopAbs_ShapeEnum aTypeBase = aShapeBase.ShapeType();
+
+ //if for section was specified face with a few wires then a few
+ // pipes were build and make solid
+ Standard_Boolean NeedCreateSolid = Standard_False;
+ if (aTypeBase == TopAbs_SHELL) {
+ // create wire as boundary contour if shell is no closed
+ // get free boundary shapes
+ ShapeAnalysis_FreeBounds anAnalizer(aShapeBase);
+ TopoDS_Compound aClosed = anAnalizer.GetClosedWires();
+ TopExp_Explorer anExp;
+ TopoDS_Shape aWire;
+ Standard_Integer NbWires = 0;
+ for (anExp.Init(aClosed, TopAbs_WIRE); anExp.More(); anExp.Next()) {
+ NbWires++;
+ aWire = anExp.Current();
+ }
+ if (NbWires != 1) {
+ // bad case
+ Standard_ConstructionError::Raise("Bad shell is used as section ");
+ }
+ NeedCreateSolid = Standard_True;
+ aSeqFaces.Append(aShapeBase);
+ aSeqBases.Append(aWire);
+ }
+ else if (aTypeBase == TopAbs_FACE) {
+ NeedCreateSolid = Standard_True;
+ //for case one path should be used other type function
+ aSeqFaces.Append(aShapeBase);
+ TopExp_Explorer aExpW(aShapeBase,TopAbs_WIRE);
+ for (; aExpW.More(); aExpW.Next()) {
+ TopoDS_Shape aWireProf = aExpW.Current();
+ aSeqBases.Append(aWireProf);
+ }
+ }
+ else if (aTypeBase == TopAbs_WIRE || aTypeBase == TopAbs_VERTEX) {
+ aSeqBases.Append(aShapeBase);
+ }
+ else if (aTypeBase == TopAbs_EDGE) {
+ TopoDS_Edge anEdge = TopoDS::Edge(aShapeBase);
+ TopoDS_Shape aWireProf = BRepBuilderAPI_MakeWire(anEdge);
+ aSeqBases.Append(aWireProf);
+ }
+ if (nbLocs) {
+ TopoDS_Shape aShapeLoc = theHSeqLocs->Value(i);
+ if (aShapeLoc.IsNull() || aShapeLoc.ShapeType() != TopAbs_VERTEX)
+ continue;
+ aSeqLocs.Append(aShapeLoc);
+ }
+ }
+
+ nbLocs = aSeqLocs.Length();
+
+ // skl 02.05.2007
+ TopTools_SequenceOfShape Edges;
+ if (nbLocs > 0) {
+ // we have to check that each location shape is a vertex from
+ // path and update aSeqLocs if it is needed (and possible)
+ TColgp_SequenceOfPnt PLocs;
+ for (i=1; i<=nbLocs; i++) {
+ TopoDS_Vertex V = TopoDS::Vertex(aSeqLocs.Value(i));
+ PLocs.Append(BRep_Tool::Pnt(V));
+ }
+ //TopTools_SequenceOfShape Edges;
+ TopExp_Explorer anExp;
+ for (anExp.Init(aWirePath, TopAbs_EDGE); anExp.More(); anExp.Next()) {
+ Edges.Append(anExp.Current());
+ }
+ int nbEdges = Edges.Length();
+ ShapeAnalysis_Edge sae;
+ TopoDS_Edge edge = TopoDS::Edge(Edges.First());
+ double tol = BRep_Tool::Tolerance(edge);
+ TopoDS_Vertex VF = sae.FirstVertex(edge);
+ gp_Pnt PF = BRep_Tool::Pnt(VF);
+ //cout<<"PF("<<PF.X()<<","<<PF.Y()<<","<<PF.Z()<<")"<<endl;
+ if (PF.Distance(PLocs.First()) > tol) {
+ Standard_ConstructionError::Raise
+ ("First location shapes is not coincided with first vertex of aWirePath");
+ }
+ aSeqLocs.ChangeValue(1) = VF;
+ edge = TopoDS::Edge(Edges.Last());
+ tol = BRep_Tool::Tolerance(edge);
+ TopoDS_Vertex VL = sae.LastVertex(edge);
+ gp_Pnt PL = BRep_Tool::Pnt(VL);
+ if (PL.Distance(PLocs.Last()) > tol) {
+ Standard_ConstructionError::Raise
+ ("Last location shapes is not coincided with last vertex of aWirePath");
+ }
+ aSeqLocs.ChangeValue(nbLocs) = VL;
+ int jcurr = 2;
+ for (i=1; i<=Edges.Length() && jcurr<nbLocs; i++) {
+ TopoDS_Edge E = TopoDS::Edge(Edges.Value(i));
+ tol = BRep_Tool::Tolerance(edge);
+ TopoDS_Vertex V1 = sae.FirstVertex(E);
+ TopoDS_Vertex V2 = sae.LastVertex(E);
+ gp_Pnt P1 = BRep_Tool::Pnt(V1);
+ gp_Pnt P2 = BRep_Tool::Pnt(V2);
+ if (P2.Distance(PLocs.Value(jcurr)) < tol) {
+ aSeqLocs.ChangeValue(jcurr) = V2;
+ jcurr++;
+ }
+ else {
+ // find distance between E and aLocs(jcurr)
+ double fp,lp;
+ Handle(Geom_Curve) C = BRep_Tool::Curve(E,fp,lp);
+ GeomAPI_ProjectPointOnCurve PPCurve (PLocs.Value(jcurr),C);
+ if (PPCurve.NbPoints()>0 &&
+ PLocs.Value(jcurr).Distance(PPCurve.Point(1)) < tol) {
+ double param = PPCurve.Parameter(1);
+ gp_Pnt PC1;
+ C->D0(param,PC1);
+ // split current edge
+ Handle(Geom_TrimmedCurve) tc1 = new Geom_TrimmedCurve(C,fp,param);
+ Handle(Geom_TrimmedCurve) tc2 = new Geom_TrimmedCurve(C,param,lp);
+ TopoDS_Edge E1,E2;
+ BRep_Builder B;
+ gp_Pnt Pfp;
+ C->D0(fp,Pfp);
+ if (Pfp.Distance(P1)<tol) {
+ B.MakeEdge(E1,tc1,tol);
+ B.Add(E1,V1);
+ TopoDS_Shape tmpV = aSeqLocs.Value(jcurr).Oriented(TopAbs_REVERSED);
+ B.Add(E1,TopoDS::Vertex(tmpV));
+ B.MakeEdge(E2,tc2,tol);
+ tmpV = aSeqLocs.Value(jcurr).Oriented(TopAbs_FORWARD);
+ B.Add(E2,TopoDS::Vertex(tmpV));
+ B.Add(E2,V2);
+ }
+ else {
+ B.MakeEdge(E1,tc2,tol);
+ TopoDS_Shape tmpV = aSeqLocs.Value(jcurr).Oriented(TopAbs_FORWARD);
+ B.Add(E1,TopoDS::Vertex(tmpV));
+ B.Add(E1,V1);
+ E1.Reverse();
+ B.MakeEdge(E2,tc1,tol);
+ B.Add(E2,V2);
+ tmpV = aSeqLocs.Value(jcurr).Oriented(TopAbs_REVERSED);
+ B.Add(E2,TopoDS::Vertex(tmpV));
+ E2.Reverse();
+ }
+ jcurr++;
+ Edges.Remove(i);
+ Edges.InsertAfter(i-1,E1);
+ Edges.InsertAfter(i,E2);
+ }
+ }
+ }
+ if (nbEdges<Edges.Length()) {
+ // one of edges was splitted => we have to update WirePath
+ BRep_Builder B;
+ TopoDS_Wire W;
+ B.MakeWire(W);
+ for (i=1; i<=Edges.Length(); i++) {
+ B.Add(W,TopoDS::Edge(Edges.Value(i)));
+ }
+ aWirePath = W;
+ }
+ }
+
+ // check curvature of wire for condition that
+ // max summary angle between directions along
+ // wire path must be < 4*PI. If not - split wire
+ // and seguences of shapes, perform pipe for each
+ // and make sewing after that
+ double fp,lp;
+ Handle(Geom_Curve) C = BRep_Tool::Curve(TopoDS::Edge(Edges.Value(1)),fp,lp);
+ gp_Pnt P1,P2;
+ gp_Vec Vec1,Vec2;
+ C->D1(fp,P1,Vec1);
+ C->D1(lp,P2,Vec2);
+ double SumAng = fabs(Vec1.Angle(Vec2));
+ Vec1 = Vec2;
+ P1 = P2;
+ TColStd_SequenceOfInteger SplitEdgeNums,SplitLocNums;
+ int LastLoc = 1;
+ //cout<<"Edges.Length()="<<Edges.Length()<<endl;
+ for (i=2; i<=Edges.Length(); i++) {
+ TopoDS_Edge edge = TopoDS::Edge(Edges.Value(i));
+ double tol = BRep_Tool::Tolerance(edge);
+ Handle(Geom_Curve) C = BRep_Tool::Curve(edge,fp,lp);
+ C->D1(lp,P2,Vec2);
+ double ang = fabs(Vec1.Angle(Vec2));
+ SumAng += ang;
+ if (SumAng>4*PI) {
+ SumAng = ang;
+ SplitEdgeNums.Append(i-1);
+ int j;
+ for (j=LastLoc+1; j<=aSeqLocs.Length(); j++) {
+ TopoDS_Vertex aVert = TopoDS::Vertex(aSeqLocs.Value(j));
+ gp_Pnt P = BRep_Tool::Pnt(aVert);
+ if (P1.Distance(P) < tol) {
+ SplitLocNums.Append(j);
+ LastLoc = j;
+ break;
+ }
+ }
+ }
+ Vec1 = Vec2;
+ P1 = P2;
+ }
+
+ if (SplitLocNums.Length()==SplitEdgeNums.Length() && SplitEdgeNums.Length()>0) {
+ TopTools_SequenceOfShape aSeqRes;
+ int nn, num1 = 1, num2 = 1;
+ for (nn=1; nn<=SplitEdgeNums.Length(); nn++) {
+ // create wirepath and sequences of shapes
+ BRep_Builder B;
+ TopoDS_Wire tmpW;
+ B.MakeWire(tmpW);
+ for (i=num1; i<=SplitEdgeNums.Value(nn); i++) {
+ B.Add(tmpW,TopoDS::Edge(Edges.Value(i)));
+ }
+ num1 = SplitEdgeNums.Value(nn) + 1;
+ TopTools_SequenceOfShape aTmpSeqBases;
+ TopTools_SequenceOfShape aTmpSeqLocs;
+ for (i=num2; i<=SplitLocNums.Value(nn); i++) {
+ aTmpSeqBases.Append(aSeqBases.Value(i));
+ aTmpSeqLocs.Append(aSeqLocs.Value(i));
+ }
+ num2 = SplitLocNums.Value(nn);
+ // make pipe
+ BRepOffsetAPI_MakePipeShell aBuilder(tmpW);
+ Standard_Integer nbShapes = aTmpSeqBases.Length();
+ for (i=1; i<=nbShapes; i++) {
+ TopoDS_Shape aShapeLoc = aTmpSeqLocs.Value(i);
+ TopoDS_Vertex aVert = TopoDS::Vertex(aShapeLoc);
+ aBuilder.Add(aTmpSeqBases.Value(i), aVert, theWithContact, theWithCorrect);
+ }
+ if (!aBuilder.IsReady()) {
+ Standard_ConstructionError::Raise("Invalid input data for building PIPE: bases are invalid");
+ }
+ aBuilder.Build();
+ TopoDS_Shape resShape = aBuilder.Shape();
+ aSeqRes.Append(resShape);
+ }
+ // create wirepath and sequences of shapes for last part
+ BRep_Builder B;
+ TopoDS_Wire tmpW;
+ B.MakeWire(tmpW);
+ for (i=num1; i<=Edges.Length(); i++) {
+ B.Add(tmpW,TopoDS::Edge(Edges.Value(i)));
+ }
+ TopTools_SequenceOfShape aTmpSeqBases;
+ TopTools_SequenceOfShape aTmpSeqLocs;
+ for (i=num2; i<=aSeqLocs.Length(); i++) {
+ aTmpSeqBases.Append(aSeqBases.Value(i));
+ aTmpSeqLocs.Append(aSeqLocs.Value(i));
+ }
+ // make pipe for last part
+ BRepOffsetAPI_MakePipeShell aBuilder(tmpW);
+ Standard_Integer nbShapes = aTmpSeqBases.Length();
+ for (i=1; i<=nbShapes; i++) {
+ TopoDS_Shape aShapeLoc = aTmpSeqLocs.Value(i);
+ TopoDS_Vertex aVert = TopoDS::Vertex(aShapeLoc);
+ aBuilder.Add(aTmpSeqBases.Value(i), aVert, theWithContact, theWithCorrect);
+ }
+ if (!aBuilder.IsReady()) {
+ Standard_ConstructionError::Raise("Invalid input data for building PIPE: bases are invalid");
+ }
+ aBuilder.Build();
+ TopoDS_Shape resShape = aBuilder.Shape();
+ aSeqRes.Append(resShape);
+ // make sewing for result
+ Handle(BRepBuilderAPI_Sewing) aSewing = new BRepBuilderAPI_Sewing;
+ aSewing->SetTolerance(Precision::Confusion());
+ aSewing->SetFaceMode(Standard_True);
+ aSewing->SetFloatingEdgesMode(Standard_False);
+ aSewing->SetNonManifoldMode(Standard_False);
+ for (i=1; i<=aSeqRes.Length(); i++) {
+ aSewing->Add(aSeqRes.Value(i));
+ }
+ aSewing->Perform();
+ aShape = aSewing->SewedShape();
+ }
+ else {
+ // old implementation without splitting
+ BRepOffsetAPI_MakePipeShell aBuilder(aWirePath);
+
+ Standard_Integer nbShapes = aSeqBases.Length();
+ Standard_Integer step = nbShapes/nbBases;
+
+ if (nbShapes < nbBases || fmod((double)nbShapes, (double)nbBases)) {
+ Standard_ConstructionError::Raise("Invalid sections were specified for building pipe");
+ }
+ Standard_Integer ind =0;
+ for (i = 1; i <= nbShapes && ind < nbShapes; i++) { //i+nbBases <= nbShapes
+ TopTools_SequenceOfShape usedBases;
+ Standard_Integer j = 1;
+ for (; j <= nbBases; j++) {
+ ind = i + (j-1)*step;
+ TopoDS_Shape aWireProf = aSeqBases.Value(ind);
+ usedBases.Append(aWireProf);
+ if (nbLocs) {
+ TopoDS_Shape aShapeLoc = aSeqLocs.Value(j);
+ TopoDS_Vertex aVert = TopoDS::Vertex(aShapeLoc);
+ aBuilder.Add(aWireProf, aVert, theWithContact, theWithCorrect);
+ }
+ else
+ aBuilder.Add(aWireProf, theWithContact, theWithCorrect);
+ }
+ if (!aBuilder.IsReady()) {
+ Standard_ConstructionError::Raise("Invalid input data for building PIPE: bases are invalid");
+ }
+ aBuilder.Build();
+ aShape = aBuilder.Shape();
+ aSeqFaces.Append(aShape);
+ for (j = 1; j <=usedBases.Length(); j++)
+ aBuilder.Delete(usedBases.Value(j));
+ }
+
+ //for case if section is face
+ if (aSeqFaces.Length() >1) {
+ BRep_Builder aB;
+ TopoDS_Compound aComp;
+ aB.MakeCompound(aComp);
+ for (i = 1; i <= aSeqFaces.Length(); i++)
+ aB.Add(aComp,aSeqFaces.Value(i));
+ aShape = aComp;
+ }
+ }
+
+ return aShape;
+}
+