0028017: Unexpected result of General Fuse operation
authormsv <msv@opencascade.com>
Fri, 16 Dec 2016 08:59:13 +0000 (11:59 +0300)
committerapn <apn@opencascade.com>
Fri, 16 Dec 2016 08:59:40 +0000 (11:59 +0300)
Several improvements have been made in BO code to fix the bug:

- Create empty edge-edge interference if intersection is close to an end vertex. This will help to avoid creation of unnecessary edge-face intersections.
- Improve PutPaveOnCurve() method to join nearly located vertices when they are put on the same section curve.
- Add processing of same-domain vertices for section edges in UpdatePaveBlocks() method.
- Improve the method CorrectWires() in order to not increase vertex tolerance if it will cover the major part of an edge.
- Replace vertices of section edges by same-domain equivalents.
- In the algorithm BOPAlgo_WireSplitter, correct angles computation and evaluation, taking into account periodicity.
- Modify PostTreatFF to properly take into account the orientations of coinciding section edges.
- In IntTools_Context::ComputePE, check distance from the point to vertices of the edge if the projection to the curve is failure.

Tests update:
- test offset\faces_type_i\C9 has been updated; now instead of returning bad shape it returns null result.

Notes for porting:
- Modify BopAlgo_PaveFiller so that on output each interference refers to the new vertex that will hit in the result (same-domain of the initial new vertex).
- Make the method BOPDS_DS::Index() returning valid index for new shapes.

// eliminate compile warning on VC14

13 files changed:
src/BOPAlgo/BOPAlgo_PaveFiller.cxx
src/BOPAlgo/BOPAlgo_PaveFiller.hxx
src/BOPAlgo/BOPAlgo_PaveFiller_11.cxx
src/BOPAlgo/BOPAlgo_PaveFiller_3.cxx
src/BOPAlgo/BOPAlgo_PaveFiller_6.cxx
src/BOPAlgo/BOPAlgo_WireSplitter_1.cxx
src/BOPDS/BOPDS_DS.cxx
src/BOPDS/BOPDS_DS.hxx
src/BOPTest/BOPTest_DebugCommands.cxx
src/BOPTools/BOPTools_AlgoTools_1.cxx
src/IntTools/IntTools_Context.cxx
tests/bugs/modalg_6/bug28017 [new file with mode: 0644]
tests/offset/faces_type_i/C9

index 408a71d..247a5b8 100644 (file)
@@ -301,6 +301,7 @@ void BOPAlgo_PaveFiller::PerformInternal()
     return; 
   }
   //
+  UpdateInterfsWithSDVertices();
   RefineFaceInfoOn();
   //
   MakePCurves();
index a4ad488..70bcba8 100644 (file)
@@ -224,7 +224,6 @@ protected:
 
   //! Treatment of section edges.
   Standard_EXPORT Standard_Integer PostTreatFF (BOPDS_IndexedDataMapOfShapeCoupleOfPaveBlocks& theMSCPB,
-                                                BOPCol_DataMapOfShapeInteger& theMVI,
                                                 BOPDS_DataMapOfPaveBlockListOfPaveBlock& theDMExEdges,
                                                 BOPCol_DataMapOfIntegerInteger& theDMNewSD,
                                                 const BOPCol_IndexedMapOfShape& theMicroEdges,
@@ -357,7 +356,9 @@ protected:
   Standard_EXPORT void UpdateCommonBlocksWithSDVertices();
    
   Standard_EXPORT void UpdateBlocksWithSharedVertices();
-   
+
+  Standard_EXPORT void UpdateInterfsWithSDVertices();
+
   Standard_EXPORT Standard_Boolean EstimatePaveOnCurve(const Standard_Integer nV,
                                                        const BOPDS_Curve& theNC,
                                                        const Standard_Real theTolR3D);
index dcc6309..742155a 100644 (file)
@@ -230,3 +230,41 @@ void BOPAlgo_PaveFiller::UpdateCommonBlocksWithSDVertices()
   }
   UpdatePaveBlocksWithSDVertices();
 }
+
+namespace
+{
+  //=======================================================================
+  //function : UpdateInterfsWithSDVertices
+  //purpose  : 
+  //=======================================================================
+  template <class InterfType>
+  void UpdateIntfsWithSDVertices(BOPDS_PDS theDS, BOPCol_NCVector<InterfType>& theInterfs)
+  {
+    for (Standard_Integer i = 0; i < theInterfs.Length(); i++)
+    {
+      InterfType& anIntf = theInterfs(i);
+      Standard_Integer anInd;
+      if (anIntf.HasIndexNew(anInd))
+      {
+        Standard_Integer anIndSD;
+        if (theDS->HasShapeSD(anInd, anIndSD))
+        {
+          anIntf.SetIndexNew(anIndSD);
+        }
+      }
+    }
+  }
+}
+
+//=======================================================================
+//function : UpdateInterfsWithSDVertices
+//purpose  : 
+//=======================================================================
+void BOPAlgo_PaveFiller::UpdateInterfsWithSDVertices()
+{
+  UpdateIntfsWithSDVertices(myDS, myDS->InterfVV());
+  UpdateIntfsWithSDVertices(myDS, myDS->InterfVE());
+  UpdateIntfsWithSDVertices(myDS, myDS->InterfVF());
+  UpdateIntfsWithSDVertices(myDS, myDS->InterfEE());
+  UpdateIntfsWithSDVertices(myDS, myDS->InterfEF());
+}
index 805ff4a..030f6a9 100644 (file)
@@ -534,6 +534,9 @@ void BOPAlgo_PaveFiller::PerformEE()
             }
           }
           if (bFlag) {
+            BOPDS_InterfEE& aEE = aEEs.Append1();
+            aEE.SetIndices(nE1, nE2);
+            aEE.SetCommonPart(aCPart);
             continue;
           }
           //
index 95e1991..1a36c18 100644 (file)
@@ -662,7 +662,7 @@ void BOPAlgo_PaveFiller::MakeBlocks()
   // 
   // post treatment
   MakeSDVerticesFF(aDMVLV, aDMNewSD);
-  myErrorStatus=PostTreatFF(aMSCPB, aMVI, aDMExEdges, aDMNewSD, aMicroEdges, aAllocator);
+  myErrorStatus=PostTreatFF(aMSCPB, aDMExEdges, aDMNewSD, aMicroEdges, aAllocator);
   if (myErrorStatus) {
     return;
   }
@@ -713,7 +713,6 @@ void BOPAlgo_PaveFiller::MakeSDVerticesFF
 //=======================================================================
 Standard_Integer BOPAlgo_PaveFiller::PostTreatFF
     (BOPDS_IndexedDataMapOfShapeCoupleOfPaveBlocks& theMSCPB,
-     BOPCol_DataMapOfShapeInteger& aMVI,
      BOPDS_DataMapOfPaveBlockListOfPaveBlock& aDMExEdges,
      BOPCol_DataMapOfIntegerInteger& aDMNewSD,
      const BOPCol_IndexedMapOfShape& theMicroEdges,
@@ -784,9 +783,25 @@ Standard_Integer BOPAlgo_PaveFiller::PostTreatFF
   }
   //
   // 1 prepare arguments
+  BOPCol_MapOfShape anAddedSD;
   for (k=1; k<=aNbS; ++k) {
     const TopoDS_Shape& aS=theMSCPB.FindKey(k);
     aLS.Append(aS);
+    // add vertices-candidates for SD from the map aDMNewSD,
+    // so that they took part in fuse operation.
+    TopoDS_Iterator itV(aS);
+    for (; itV.More(); itV.Next())
+    {
+      const TopoDS_Shape& aVer = itV.Value();
+      Standard_Integer iVer = myDS->Index(aVer);
+      const Standard_Integer* pSD = aDMNewSD.Seek(iVer);
+      if (pSD)
+      {
+        const TopoDS_Shape& aVSD = myDS->Shape(*pSD);
+        if (anAddedSD.Add(aVSD))
+          aLS.Append(aVSD);
+      }
+    }
   }
   //
   // The section edges considered as a micro should be
@@ -849,32 +864,28 @@ Standard_Integer BOPAlgo_PaveFiller::PostTreatFF
         aV=aSx;
       }
       // index of new vertex in theDS -> iV
-      if (!aMVI.IsBound(aV)) {
+      iV = myDS->Index(aV);
+      if (iV < 0) {
         aSI.SetShapeType(aType);
         aSI.SetShape(aV);
         iV=myDS->Append(aSI);
-        //
-        aMVI.Bind(aV, iV);
-      }
-      else {
-        iV=aMVI.Find(aV);
       }
       //
       if (!bIntersectionPoint) {
         // save SD connection
-        nSx = aMVI.Find(aSx);
+        nSx = myDS->Index(aSx);
         aDMNewSD.Bind(nSx, iV);
         myDS->AddShapeSD(nSx, iV);
       }
       else {
-      // update FF interference
-      const BOPDS_CoupleOfPaveBlocks &aCPB=theMSCPB.FindFromKey(aSx);
-      iX=aCPB.IndexInterf();
-      iP=aCPB.Index();
-      BOPDS_InterfFF& aFF=aFFs(iX);
-      BOPDS_VectorOfPoint& aVNP=aFF.ChangePoints();
-      BOPDS_Point& aNP=aVNP(iP);
-      aNP.SetIndex(iV);
+        // update FF interference
+        const BOPDS_CoupleOfPaveBlocks &aCPB=theMSCPB.FindFromKey(aSx);
+        iX=aCPB.IndexInterf();
+        iP=aCPB.Index();
+        BOPDS_InterfFF& aFF=aFFs(iX);
+        BOPDS_VectorOfPoint& aVNP=aFF.ChangePoints();
+        BOPDS_Point& aNP=aVNP(iP);
+        aNP.SetIndex(iV);
       }
     }//if (aType==TopAbs_VERTEX) {
     //
@@ -944,14 +955,11 @@ Standard_Integer BOPAlgo_PaveFiller::PostTreatFF
         if (!aNbLPBx) {
           aE=aSx;
           //
-          if (!aMVI.IsBound(aE)) {
+          iE = myDS->Index(aE);
+          if (iE < 0) {
             aSI.SetShapeType(aType);
             aSI.SetShape(aE);
             iE=myDS->Append(aSI);
-            aMVI.Bind(aE, iE);
-          }
-          else {
-            iE=aMVI.Find(aE);
           }
           // append new PaveBlock to aLPBC
           aPB1->SetEdge(iE);
@@ -965,21 +973,17 @@ Standard_Integer BOPAlgo_PaveFiller::PostTreatFF
             const Handle(BOPDS_PaveBlock) aPBRx=aPDS->RealPaveBlock(aPBx);
             //
             // update vertices of paves
-            aPave[0]=aPBx->Pave1();
-            aPave[1]=aPBx->Pave2();
+            aPave[0] = aPBx->Pave1();
+            aPave[1] = aPBx->Pave2();
             for (j=0; j<2; ++j) {
               nV = aPave[j].Index();
               aV = aPDS->Shape(nV);
-              //
-              if (!aMVI.IsBound(aV)) {
-                // index of new vertex in theDS -> iV
+              // index of new vertex in myDS -> iV
+              iV = myDS->Index(aV);
+              if (iV < 0) {
                 aSI.SetShapeType(TopAbs_VERTEX);
                 aSI.SetShape(aV);
                 iV = myDS->Append(aSI);
-                aMVI.Bind(aV, iV);
-              }
-              else {
-                iV = aMVI.Find(aV);
               }
               const BOPDS_Pave& aP1 = !j ? aPB1->Pave1() : aPB1->Pave2();
               if (aP1.Parameter() == aPave[j].Parameter() && 
@@ -993,29 +997,31 @@ Standard_Integer BOPAlgo_PaveFiller::PostTreatFF
             //
             // add edge
             aE=aPDS->Shape(aPBRx->Edge());
+            iE = myDS->Index(aE);
             //
-            if (!aMVI.IsBound(aE)) {
+            if (iE < 0) {
               aSI.SetShapeType(aType);
               aSI.SetShape(aE);
               iE=myDS->Append(aSI);
-              aMVI.Bind(aE, iE);
               // update real edge tolerance according to distances in common block if any
-              if (aPDS->IsCommonBlock(aPBx)) {
-                const Handle(BOPDS_CommonBlock)& aCB = aPDS->CommonBlock(aPBx);
+              if (aPDS->IsCommonBlock(aPBRx)) {
+                const Handle(BOPDS_CommonBlock)& aCB = aPDS->CommonBlock(aPBRx);
                 Standard_Real aTol = BOPAlgo_Tools::ComputeToleranceOfCB(aCB, aPDS, aPF.Context());
                 if (aFF.TolReal() < aTol) {
                   aFF.SetTolReal(aTol);
                 }
               }
             }
-            else {
-              iE=aMVI.Find(aE);
-            }
             // append new PaveBlock to aLPBC
             Handle(BOPDS_PaveBlock) aPBC=new BOPDS_PaveBlock();
+            BOPDS_Pave aPaveR1, aPaveR2;
+            aPaveR1 = aPBRx->Pave1();
+            aPaveR2 = aPBRx->Pave2();
+            aPaveR1.SetIndex(myDS->Index(aPDS->Shape(aPaveR1.Index())));
+            aPaveR2.SetIndex(myDS->Index(aPDS->Shape(aPaveR2.Index())));
             //
-            aPBC->SetPave1(aPave[0]);
-            aPBC->SetPave2(aPave[1]);
+            aPBC->SetPave1(aPaveR1);
+            aPBC->SetPave2(aPaveR2);
             aPBC->SetEdge(iE);
             if (bOld) {
               aPBC->SetOriginalEdge(aPB1->OriginalEdge());
@@ -1029,6 +1035,18 @@ Standard_Integer BOPAlgo_PaveFiller::PostTreatFF
       }
     }//else if (aType==TopAbs_EDGE)
   }//for (; aItLS.More(); aItLS.Next()) {
+
+  // Update SD for vertices that did not participate in operation
+  BOPCol_DataMapOfIntegerInteger::Iterator itDM(aDMNewSD);
+  for (; itDM.More(); itDM.Next())
+  {
+    const Standard_Integer* pSD = aDMNewSD.Seek(itDM.Value());
+    if (pSD)
+    {
+      itDM.ChangeValue() = *pSD;
+      myDS->AddShapeSD(itDM.Key(), *pSD);
+    }
+  }
   return iRet;
 }
 
@@ -2036,7 +2054,7 @@ void BOPAlgo_PaveFiller::PutPaveOnCurve
     aDTol = 1.e-12;
     //
     GeomAdaptor_Curve aGAC(aIC.Curve());
-    aPTol = aGAC.Resolution(aTolR3D);
+    aPTol = aGAC.Resolution(Max(aTolR3D, aTolV));
     //
     bExist = aPB->ContainsParameter(aT, aPTol, nVUsed);
     if (bExist) {
@@ -2451,71 +2469,95 @@ void BOPAlgo_PaveFiller::UpdatePaveBlocks
   BOPDS_MapOfPaveBlock aMPB;
   BOPCol_MapOfInteger aMicroEdges;
   //
+  BOPDS_ListOfPaveBlock anAllPBs;
+
+  // Get pave blocks of section edges
+  BOPDS_VectorOfInterfFF& aFFs = myDS->InterfFF();
+  Standard_Integer aNbFF = aFFs.Extent();
+  for (i = 0; i < aNbFF; ++i)
+  {
+    const BOPDS_InterfFF& aFF = aFFs(i);
+    const BOPDS_VectorOfCurve& aVNC = aFF.Curves();
+    Standard_Integer aNbC = aVNC.Extent();
+    for (j = 0; j < aNbC; ++j)
+    {
+      const BOPDS_Curve& aNC = aVNC(j);
+      const BOPDS_ListOfPaveBlock& aLPBC = aNC.PaveBlocks();
+      aItPB.Initialize(aLPBC);
+      for (; aItPB.More(); aItPB.Next())
+        anAllPBs.Append(aItPB.Value());
+    }
+  }
+
+  // Get pave blocks from the pool
   BOPDS_VectorOfListOfPaveBlock& aPBP = myDS->ChangePaveBlocksPool();
   aNbPBP = aPBP.Extent();
   for (i = 0; i < aNbPBP; ++i) {
     BOPDS_ListOfPaveBlock& aLPB = aPBP(i);
-    //
     aItPB.Initialize(aLPB);
-    for (; aItPB.More(); aItPB.Next()) {
-      Handle(BOPDS_PaveBlock) aPB = aItPB.Value();
-      const Handle(BOPDS_CommonBlock)& aCB = myDS->CommonBlock(aPB);
-      bCB = !aCB.IsNull();
-      if (bCB) {
-        aPB = aCB->PaveBlock1();
-      }
+    for (; aItPB.More(); aItPB.Next())
+      anAllPBs.Append(aItPB.Value());
+  }
+
+  // Process all pave blocks
+  aItPB.Initialize(anAllPBs);
+  for (; aItPB.More(); aItPB.Next())
+  {
+    Handle(BOPDS_PaveBlock) aPB = aItPB.Value();
+    const Handle(BOPDS_CommonBlock)& aCB = myDS->CommonBlock(aPB);
+    bCB = !aCB.IsNull();
+    if (bCB) {
+      aPB = aCB->PaveBlock1();
+    }
+    //
+    if (aMPB.Add(aPB)) {
+      bRebuild = Standard_False;
+      aPB->Indices(nV[0], nV[1]);
+      aPB->Range(aT[0], aT[1]);
+      // remember the fact if the edge had different vertices before substitution
+      Standard_Boolean wasRegularEdge = (nV[0] != nV[1]);
       //
-      if (aMPB.Add(aPB)) {
-        bRebuild = Standard_False;
-        aPB->Indices(nV[0], nV[1]);
-        aPB->Range(aT[0], aT[1]);
-        // remember the fact if the edge had different vertices before substitution
-        Standard_Boolean wasRegularEdge = (nV[0] != nV[1]);
-        //
-        for (j = 0; j < 2; ++j) {
-          if (aDMNewSD.IsBound(nV[j])) {
-            BOPDS_Pave aPave;
-            //
-            nV[j] = aDMNewSD.Find(nV[j]);
-            aPave.SetIndex(nV[j]);
-            aPave.SetParameter(aT[j]);
-            //
-            bRebuild = Standard_True;
-            if (!j) {
-              aPB->SetPave1(aPave);
-            }
-            else {
-              aPB->SetPave2(aPave);
-            }
-          }
-        }
-        //
-        if (bRebuild) {
-          Standard_Boolean isDegEdge = myDS->ShapeInfo(aPB->Edge()).HasFlag();
-          if (wasRegularEdge && !isDegEdge && nV[0] == nV[1]) {
-            // now edge has the same vertex on both ends;
-            // check if it is not a regular closed curve.
-            const TopoDS_Edge& aE = TopoDS::Edge(myDS->Shape(aPB->Edge()));
-            const TopoDS_Vertex& aV = TopoDS::Vertex(myDS->Shape(nV[0]));
-            Standard_Real aLength = IntTools::Length(aE);
-            Standard_Real aTolV = BRep_Tool::Tolerance(aV);
-            if (aLength <= aTolV * 2.) {
-              // micro edge, so mark it for removal
-              aMicroEdges.Add(aPB->Edge());
-              continue;
-            }
-          }
-          nSp = SplitEdge(aPB->OriginalEdge(), nV[0], aT[0], nV[1], aT[1]);
-          if (bCB) {
-            aCB->SetEdge(nSp);
+      for (j = 0; j < 2; ++j) {
+        if (aDMNewSD.IsBound(nV[j])) {
+          BOPDS_Pave aPave;
+          //
+          nV[j] = aDMNewSD.Find(nV[j]);
+          aPave.SetIndex(nV[j]);
+          aPave.SetParameter(aT[j]);
+          //
+          bRebuild = Standard_True;
+          if (!j) {
+            aPB->SetPave1(aPave);
           }
           else {
-            aPB->SetEdge(nSp);
+            aPB->SetPave2(aPave);
+          }
+        }
+      }
+      //
+      if (bRebuild) {
+        Standard_Boolean isDegEdge = myDS->ShapeInfo(aPB->Edge()).HasFlag();
+        if (wasRegularEdge && !isDegEdge && nV[0] == nV[1]) {
+          // now edge has the same vertex on both ends;
+          // check if it is not a regular closed curve.
+          const TopoDS_Edge& aE = TopoDS::Edge(myDS->Shape(aPB->Edge()));
+          const TopoDS_Vertex& aV = TopoDS::Vertex(myDS->Shape(nV[0]));
+          Standard_Real aLength = IntTools::Length(aE);
+          Standard_Real aTolV = BRep_Tool::Tolerance(aV);
+          if (aLength <= aTolV * 2.) {
+            // micro edge, so mark it for removal
+            aMicroEdges.Add(aPB->Edge());
+            continue;
           }
-        }// if (bRebuild) {
-      }// if (aMPB.Add(aPB)) {
-    }// for (; aItPB.More(); aItPB.Next()) {
-  }// for (i=0; i<aNbPBP; ++i) {
+        }
+        nSp = SplitEdge(aPB->Edge(), nV[0], aT[0], nV[1], aT[1]);
+        if (bCB)
+          aCB->SetEdge(nSp);
+        else
+          aPB->SetEdge(nSp);
+      }// if (bRebuild) {
+    }// if (aMPB.Add(aPB)) {
+  }// for (; aItPB.More(); aItPB.Next()) {
   aMPB.Clear();
 
   if (aMicroEdges.Extent())
@@ -2765,20 +2807,20 @@ void BOPAlgo_PaveFiller::CorrectToleranceOfSE()
     Standard_Real aTolR3D = aFF.TolR3D();
     Standard_Real aTolReal = aFF.TolReal();
     Standard_Boolean bToReduce = aTolReal < aTolR3D;
-      // tolerance of intersection has been increased, so process this intersection
+    // tolerance of intersection has been increased, so process this intersection
     BOPDS_VectorOfCurve& aVNC = aFF.ChangeCurves();
-      Standard_Integer aNbC = aVNC.Extent(), k;
-      for (k = 0; k < aNbC; ++k) {
+    Standard_Integer aNbC = aVNC.Extent(), k;
+    for (k = 0; k < aNbC; ++k) {
       BOPDS_Curve& aNC = aVNC(k);
       BOPDS_ListOfPaveBlock& aLPB = aNC.ChangePaveBlocks();
-        BOPDS_ListIteratorOfListOfPaveBlock aItLPB(aLPB);
+      BOPDS_ListIteratorOfListOfPaveBlock aItLPB(aLPB);
       for (; aItLPB.More(); ) {
-          const Handle(BOPDS_PaveBlock)& aPB = aItLPB.Value();
-          Standard_Integer nE;
+        const Handle(BOPDS_PaveBlock)& aPB = aItLPB.Value();
+        Standard_Integer nE;
         if (!aPB->HasEdge(nE)) {
           aLPB.Remove(aItLPB);
-            continue;
-          }
+          continue;
+        }
         //
         Standard_Boolean bIsReduced = Standard_False;
         if (bToReduce && (aPB->OriginalEdge() < 0)) {
@@ -2791,13 +2833,13 @@ void BOPAlgo_PaveFiller::CorrectToleranceOfSE()
           }
         }
         //
-          // fill in the map vertex index - pave blocks
-          for (Standard_Integer j=0; j < 2; j++) {
+        // fill in the map vertex index - pave blocks
+        for (Standard_Integer j=0; j < 2; j++) {
           Standard_Integer nV = (j == 0 ? aPB->Pave1().Index() : aPB->Pave2().Index());
-            BOPDS_ListOfPaveBlock *pPBList = aMVIPBs.ChangeSeek(nV);
-            if (!pPBList) {
-              pPBList = &aMVIPBs.ChangeFromIndex(aMVIPBs.Add(nV, BOPDS_ListOfPaveBlock()));
-            }
+          BOPDS_ListOfPaveBlock *pPBList = aMVIPBs.ChangeSeek(nV);
+          if (!pPBList) {
+            pPBList = &aMVIPBs.ChangeFromIndex(aMVIPBs.Add(nV, BOPDS_ListOfPaveBlock()));
+          }
           pPBList->Append(aPB);
           if (bIsReduced) {
             aMVIToReduce.Add(nV);
index 185d2df..e1b1bdf 100644 (file)
@@ -139,6 +139,7 @@ static
                                  const TopoDS_Face& ,
                                  const Standard_Real ,
                                  const Standard_Real ,
+                                 const Standard_Real, 
                                  Standard_Real& ,
                                  const Handle(IntTools_Context)& );
 
@@ -409,13 +410,11 @@ void Path (const GeomAdaptor_Surface& aGAS,
     aTol2D2 = aTol2D * aTol2D;
     //
     bIsClosed = aVertMap.Find(aVb);
-    //
-    aNb=aLS.Length();
-    if (aNb>0) {
-      //
+    {
       BOPCol_ListOfShape aBuf;
       //
-      for (i=aNb; i>0; --i) {
+      aNb = aLS.Length();
+      for (i = aNb; i>0; --i) {
         const TopoDS_Shape& aVPrev=aVertVa(i);
         const gp_Pnt2d& aPaPrev=aCoordVa(i);
         const TopoDS_Shape& aEPrev=aLS(i);
@@ -495,6 +494,7 @@ void Path (const GeomAdaptor_Surface& aGAS,
     anAngleIn = AngleIn(aEOuta, aLEInfo);
     aMinAngle = 100.;
     anIsFound = Standard_False;
+    Standard_Integer iCnt = NbWaysOut(aLEInfo);
     Standard_Integer aCurIndexE = 0;
     anIt.Initialize(aLEInfo);
     for (; anIt.More(); anIt.Next()) {
@@ -508,8 +508,6 @@ void Path (const GeomAdaptor_Surface& aGAS,
         //
         // Is there one way to go out of the vertex 
         // we have to use it only.
-        Standard_Integer iCnt;
-        iCnt=NbWaysOut (aLEInfo);
         //
         if (!iCnt) {
           // no way to go . (Error)
@@ -919,8 +917,8 @@ void RefineAngles(const TopoDS_Vertex& aV,
   BOPCol_DataMapOfShapeReal aDMSR;
   BOPAlgo_ListIteratorOfListOfEdgeInfo aItLEI;
   //
-  aA1=0.;
-  aA2=0.;
+  aA1=0.;  // angle of outgoing edge
+  aA2=0.;  // angle of incoming edge
   iCntBnd=0;
   iCntInt=0;
   aItLEI.Initialize(aLEI);
@@ -936,7 +934,7 @@ void RefineAngles(const TopoDS_Vertex& aV,
         aA1=aA;
       }
       else {
-        aA2=aA+M_PI;
+        aA2=aA;
       }
     }
     else {
@@ -948,6 +946,7 @@ void RefineAngles(const TopoDS_Vertex& aV,
     return;
   }
   //
+  Standard_Real aDelta = ClockWiseAngle(aA2, aA1);
   aItLEI.Initialize(aLEI);
   for (; aItLEI.More(); aItLEI.Next()) {
     BOPAlgo_EdgeInfo& aEI=aItLEI.ChangeValue();
@@ -960,11 +959,12 @@ void RefineAngles(const TopoDS_Vertex& aV,
     }
     //
     aA=aEI.Angle();
-    if (aA>aA1 && aA<aA2) {
-      continue;
+    Standard_Real aDA = ClockWiseAngle(aA2, aA);
+    if (aDA < aDelta) {
+      continue;  // already inside
     }
     //
-    bRefined=RefineAngle2D(aV, aE, myFace, aA1, aA2, aA, theContext);
+    bRefined=RefineAngle2D(aV, aE, myFace, aA1, aA2, aDelta, aA, theContext);
     if (bRefined) {
       aDMSR.Bind(aE, aA);
     }
@@ -1007,6 +1007,7 @@ Standard_Boolean RefineAngle2D(const TopoDS_Vertex& aV,
                                const TopoDS_Face& myFace,
                                const Standard_Real aA1,
                                const Standard_Real aA2,
+                               const Standard_Real aDelta,
                                Standard_Real& aA,
                                const Handle(IntTools_Context)& theContext)
 {
@@ -1033,12 +1034,13 @@ Standard_Boolean RefineAngle2D(const TopoDS_Vertex& aV,
   //
   aTOp = (fabs(aTV-aT1) < fabs(aTV-aT2)) ? aT2 : aT1;
   //
+  const Standard_Real MaxDT = 0.3 * (aT2 - aT1);
   aGAC1.D0(aT1, aP1);
   aGAC1.D0(aT2, aP2);
   aDomain1.SetValues(aP1, aT1, aTolInt, aP2, aT2, aTolInt);
   //
   for (i=0; i<2; ++i) {
-    aAi=(!i) ? aA1 : aA2;
+    aAi=(!i) ? aA1 : (aA2 + M_PI);
     aXi=cos(aAi);
     aYi=sin(aAi);
     gp_Dir2d aDiri(aXi, aYi);
@@ -1051,39 +1053,38 @@ Standard_Boolean RefineAngle2D(const TopoDS_Vertex& aV,
       continue;
     }
     //
-    aNbP=aGInter.NbPoints();
-    if (aNbP<2) {
-      continue;
-    }
-    //
-    aT1max=aTV;
-    aT2max=-1.;
-    for (j=1; j<=aNbP; ++j) {
-      const IntRes2d_IntersectionPoint& aIPj=aGInter.Point(j);
-      aT1j=aIPj.ParamOnFirst();
-      aT2j=aIPj.ParamOnSecond();
+    aNbP = aGInter.NbPoints();
+    aT1max = aTV;
+    aT2max = -1.;
+    for (j = 1; j <= aNbP; ++j) {
+      const IntRes2d_IntersectionPoint& aIPj = aGInter.Point(j);
+      aT1j = aIPj.ParamOnFirst();
+      aT2j = aIPj.ParamOnSecond();
       //
-      if (aT2j > aT2max) {
-        aT2max=aT2j;
-        aT1max=aT1j;
+      if (aT2j > aT2max && Abs(aT1j - aTV) < MaxDT) {
+        aT2max = aT2j;
+        aT1max = aT1j;
       }
     }
     //
-    dT = aTOp - aT1max;
-    if (Abs(dT) < aTolInt) {
-      continue;
-    }
-    //
-    aT=aT1max + aCf*dT;
-    aGAC1.D0(aT, aP);
-    gp_Vec2d aV2D(aPV, aP);
-    gp_Dir2d aDir2D(aV2D);
-    //
-    aAngle=Angle(aDir2D);
-    if (aAngle>aA1 && aAngle<aA2) {
-      aA=aAngle;
-      return bRet;
+    if (aT2max > 0) {
+      dT = aTOp - aT1max;
+      if (Abs(dT) < aTolInt) {
+        continue;
+      }
+      //
+      aT = aT1max + aCf*dT;
+      aGAC1.D0(aT, aP);
+      gp_Vec2d aV2D(aPV, aP);
+      gp_Dir2d aDir2D(aV2D);
+      //
+      aAngle = Angle(aDir2D);
+      Standard_Real aDA = ClockWiseAngle(aA2, aAngle);
+      if (aDA < aDelta) {
+        aA = aAngle;
+        return bRet;
+      }
     }
   }// for (i=0; i<2; ++i) {
   return !bRet;
-}
+}
\ No newline at end of file
index 8832187..89ebb38 100644 (file)
@@ -256,6 +256,7 @@ Standard_Integer BOPDS_DS::Append(const BOPDS_ShapeInfo& theSI)
   //
   myLines.Append1()=theSI;
   iX=myLines.Extent()-1;
+  myMapShapeIndex.Bind(theSI.Shape(), iX);
   //
   return iX;
 }
@@ -269,6 +270,7 @@ Standard_Integer BOPDS_DS::Append(const TopoDS_Shape& theS)
   //
   myLines.Append1().SetShape(theS);
   iX=myLines.Extent()-1;
+  myMapShapeIndex.Bind(theS, iX);
   return iX;
 }
 //=======================================================================
@@ -358,20 +360,18 @@ void BOPDS_DS::Init(const Standard_Real theFuzz)
   aAllocator=
     NCollection_BaseAllocator::CommonBaseAllocator();
   //
-  BOPCol_DataMapOfShapeInteger& aMSI=myMapShapeIndex;
   //
   i1=0; 
   i2=0;
   aIt.Initialize(myArguments);
   for (; aIt.More(); aIt.Next()) {
     const TopoDS_Shape& aS=aIt.Value();
-    if (aMSI.IsBound(aS)) {
+    if (myMapShapeIndex.IsBound(aS)) {
       continue;
     }
     aI=Append(aS);
-    aMSI.Bind(aS, aI);
     //
-    InitShape(aI, aS, aAllocator, aMSI);
+    InitShape(aI, aS);
     //
     i2=NbShapes()-1;
     aR.SetIndices(i1, i2);
@@ -658,9 +658,7 @@ void BOPDS_DS::Init(const Standard_Real theFuzz)
 //=======================================================================
 void BOPDS_DS::InitShape
   (const Standard_Integer aI,
-   const TopoDS_Shape& aS,
-   const Handle(NCollection_BaseAllocator)& theAllocator,
-   BOPCol_DataMapOfShapeInteger& aMSI)
+   const TopoDS_Shape& aS)
 {
   Standard_Integer aIx;
   TopoDS_Iterator aIt;
@@ -670,7 +668,7 @@ void BOPDS_DS::InitShape
   aSI.SetShapeType(aS.ShapeType());
   BOPCol_ListOfInteger& aLI=aSI.ChangeSubShapes();
   //
-  BOPCol_MapOfInteger aM(100, theAllocator);
+  BOPCol_MapOfInteger aM;
   //
   aIt1.Initialize(aLI);
   for (; aIt1.More(); aIt1.Next()) {
@@ -680,15 +678,10 @@ void BOPDS_DS::InitShape
   aIt.Initialize(aS);
   for (; aIt.More(); aIt.Next()) {
     const TopoDS_Shape& aSx=aIt.Value();
-    if (aMSI.IsBound(aSx)) {
-      aIx=aMSI.Find(aSx);
-    }
-    else {
-      aIx=Append(aSx);
-      aMSI.Bind(aSx, aIx);
-    }
+    const Standard_Integer* pIx = myMapShapeIndex.Seek(aSx);
+    aIx = (pIx ? *pIx : Append(aSx));
     //
-    InitShape(aIx, aSx, theAllocator, aMSI);
+    InitShape(aIx, aSx);
     //
     if (aM.Add(aIx)) {
       aLI.Append(aIx);
index a882896..2797f1c 100644 (file)
@@ -472,7 +472,7 @@ protected:
   //! Initializes the state of face with index theIndex
   Standard_EXPORT void InitFaceInfo (const Standard_Integer theIndex);
   
-  Standard_EXPORT void InitShape (const Standard_Integer theIndex, const TopoDS_Shape& theS, const BOPCol_BaseAllocator& theAllocator, BOPCol_DataMapOfShapeInteger& theMSI);
+  Standard_EXPORT void InitShape (const Standard_Integer theIndex, const TopoDS_Shape& theS);
   
   Standard_EXPORT Standard_Boolean CheckCoincidence (const Handle(BOPDS_PaveBlock)& thePB1,
                                                      const Handle(BOPDS_PaveBlock)& thePB2,
index 400c589..9434701 100644 (file)
@@ -576,21 +576,6 @@ Standard_Integer bopindex (Draw_Interpretor& di,
     di << " Index: " << ind << "\n";
   }
   else {
-    Standard_Integer i1, i2;
-    //
-    i1 = pDS->NbSourceShapes();
-    i2 = pDS->NbShapes();
-    for (ind = i1; ind < i2; ++ind) {
-      const TopoDS_Shape& aSx = pDS->Shape(ind);
-      if (aSx.IsSame(aS)) {
-        di << " Index: " << ind << "\n";
-        bFound = Standard_True;
-        break;
-      }
-    }
-  }
-  //
-  if (!bFound) {
     di << " DS does not contain the shape\n";
   }
   //
index 04141ba..f10a281 100644 (file)
@@ -30,6 +30,7 @@
 #include <BRep_Tool.hxx>
 #include <BRep_TVertex.hxx>
 #include <BRepAdaptor_Surface.hxx>
+#include <BRepAdaptor_Curve.hxx>
 #include <BRepLib_CheckCurveOnSurface.hxx>
 #include <BRepTools_WireExplorer.hxx>
 #include <Extrema_LocateExtPC.hxx>
@@ -48,6 +49,7 @@
 #include <GeomAdaptor_HSurface.hxx>
 #include <GeomAdaptor_Surface.hxx>
 #include <GeomProjLib.hxx>
+#include <GCPnts_AbscissaPoint.hxx>
 #include <gp_Pnt.hxx>
 #include <gp_Pnt2d.hxx>
 #include <IntRes2d_Domain.hxx>
@@ -116,7 +118,8 @@ static
                                   const TopoDS_Face& theF,
                                   const Handle(Geom_Surface)& theS,
                                   const TopoDS_Edge& theE1,
-                                  const TopoDS_Edge& theE2);
+                                  const TopoDS_Edge& theE2,
+                   NCollection_DataMap<TopoDS_Shape, Standard_Real>& theMapEdgeLen);
 
 //=======================================================================
 //class    : BOPTools_CPC
@@ -578,6 +581,7 @@ void CorrectWires(const TopoDS_Face& aFx,
                                 TopAbs_VERTEX, 
                                 TopAbs_EDGE, 
                                 aMVE);
+  NCollection_DataMap<TopoDS_Shape, Standard_Real> aMapEdgeLen;
   aNbV=aMVE.Extent();
   for (i=1; i<=aNbV; ++i) {
     const TopoDS_Vertex& aV=*((TopoDS_Vertex*)&aMVE.FindKey(i));
@@ -615,7 +619,7 @@ void CorrectWires(const TopoDS_Face& aFx,
           continue;
         }
         //
-        aD2 = IntersectCurves2d(aV, aF, aS, aE1, aE2);
+        aD2 = IntersectCurves2d(aV, aF, aS, aE1, aE2, aMapEdgeLen);
         if (aD2 > aD2max) {
           aD2max = aD2;
         }
@@ -630,6 +634,26 @@ void CorrectWires(const TopoDS_Face& aFx,
 }
 
 //=======================================================================
+// Function : MapEdgeLength
+// purpose  : Compute edge length and cache it in the map
+//=======================================================================
+static Standard_Real MapEdgeLength(const TopoDS_Edge& theEdge,
+                                   NCollection_DataMap<TopoDS_Shape, Standard_Real>& theMapEdgeLen)
+{
+  const Standard_Real* pLen = theMapEdgeLen.Seek(theEdge);
+  if (!pLen)
+  {
+    Standard_Real aLen = 0.;
+    if (!BRep_Tool::Degenerated(theEdge))
+    {
+      BRepAdaptor_Curve aCurve(theEdge);
+      aLen = GCPnts_AbscissaPoint::Length(aCurve);
+    }
+    pLen = theMapEdgeLen.Bound(theEdge, aLen);
+  }
+  return *pLen;
+}
+//=======================================================================
 // Function : IntersectCurves2d
 // purpose  : Intersect 2d curves of edges
 //=======================================================================
@@ -637,7 +661,8 @@ Standard_Real IntersectCurves2d(const TopoDS_Vertex& theV,
                                 const TopoDS_Face& theF,
                                 const Handle(Geom_Surface)& theS,
                                 const TopoDS_Edge& theE1,
-                                const TopoDS_Edge& theE2)
+                                const TopoDS_Edge& theE2,
+                                NCollection_DataMap<TopoDS_Shape, Standard_Real>& theMapEdgeLen)
 {
   Standard_Real aT11, aT12, aT21, aT22, aTol2d, aMaxDist;
   Geom2dInt_GInter anInter;
@@ -657,7 +682,7 @@ Standard_Real IntersectCurves2d(const TopoDS_Vertex& theV,
                         aC2D2->Value(aT22), aT22, aTol2d);
   //
   anInter.Perform(aGAC1, aDom1, aGAC2, aDom2, aTol2d, aTol2d);
-  if (!anInter.IsDone()) {
+  if (!anInter.IsDone() || (!anInter.NbSegments() && !anInter.NbPoints())) {
     return aMaxDist;
   }
   //
@@ -690,6 +715,12 @@ Standard_Real IntersectCurves2d(const TopoDS_Vertex& theV,
     aLP.Append(aPnt);
   }
   //
+  // evaluate the length of the smallest edge, so that not to return too large distance
+  Standard_Real aLen1 = MapEdgeLength(theE1, theMapEdgeLen);
+  Standard_Real aLen2 = MapEdgeLength(theE2, theMapEdgeLen);
+  const Standard_Real MaxEdgePartCoveredByVertex = 0.3;
+  Standard_Real aMaxThresDist = Min(aLen1, aLen2) * MaxEdgePartCoveredByVertex;
+  aMaxThresDist *= aMaxThresDist;
   aItLP.Initialize(aLP);
   for (; aItLP.More(); aItLP.Next()) {
     const IntRes2d_IntersectionPoint& aPnt = aItLP.Value();
@@ -712,7 +743,7 @@ Standard_Real IntersectCurves2d(const TopoDS_Vertex& theV,
     aP2d = aPnt.Value();
     theS->D0(aP2d.X(), aP2d.Y(), aP);
     aDist = aPV.SquareDistance(aP);
-    if (aDist > aMaxDist) {
+    if (aDist > aMaxDist && aDist < aMaxThresDist) {
       aMaxDist = aDist;
     }
   }
index c8c8a73..9809fbf 100644 (file)
@@ -525,18 +525,43 @@ Standard_Integer IntTools_Context::ComputePE
   aProjector.Perform(aP1);
 
   aNbProj=aProjector.NbPoints();
-  if (!aNbProj) {
-    return -3;
+  if (aNbProj)
+  {
+    // point falls on the curve
+    aDist = aProjector.LowerDistance();
+    //
+    aTolE2 = BRep_Tool::Tolerance(aE2);
+    aTolSum = aTolP1 + aTolE2 + Precision::Confusion();
+    //
+    aT = aProjector.LowerDistanceParameter();
+    if (aDist > aTolSum) {
+      return -4;
+    }
   }
-  //
-  aDist=aProjector.LowerDistance();
-  //
-  aTolE2=BRep_Tool::Tolerance(aE2);
-  aTolSum = aTolP1 + aTolE2 + Precision::Confusion();
-  //
-  aT=aProjector.LowerDistanceParameter();
-  if (aDist > aTolSum) {
-    return -4;
+  else
+  {
+    // point falls out of the curve, check distance to vertices
+    TopoDS_Edge aEFwd = TopoDS::Edge(aE2.Oriented(TopAbs_FORWARD));
+    TopoDS_Iterator itV(aEFwd);
+    aDist = RealLast();
+    for (; itV.More(); itV.Next())
+    {
+      const TopoDS_Vertex& aV = TopoDS::Vertex(itV.Value());
+      if (aV.Orientation() == TopAbs_FORWARD || aV.Orientation() == TopAbs_REVERSED)
+      {
+        gp_Pnt aPV = BRep_Tool::Pnt(aV);
+        aTolSum = aTolP1 + BRep_Tool::Tolerance(aV) + Precision::Confusion();
+        Standard_Real aDist1 = aP1.SquareDistance(aPV);
+        if (aDist1 < aDist && aDist1 < Square(aTolSum))
+        {
+          aDist = aDist1;
+          aT = BRep_Tool::Parameter(aV, aEFwd);
+        }
+      }
+    }
+    if (Precision::IsInfinite(aDist)) {
+      return -3;
+    }
   }
   return 0;
 }
diff --git a/tests/bugs/modalg_6/bug28017 b/tests/bugs/modalg_6/bug28017
new file mode 100644 (file)
index 0000000..2100f55
--- /dev/null
@@ -0,0 +1,29 @@
+puts "========"
+puts "OCC28017"
+puts "========"
+puts ""
+#################################################
+# Unexpected result of General Fuse operation
+#################################################
+
+restore [locate_data_file bug28017_shape.brep] a
+
+explode a
+bclearobjects
+bcleartools
+baddobjects a_1
+baddtools a_2
+bfillds
+bbuild r
+
+checkmaxtol r -min_tol 0.51
+explode r So
+checknbshapes r -solid 2
+checkshape r_1
+checkshape r_2
+bopcheck r_1
+bopcheck r_2
+don r_1 r_2
+smallview; fit
+
+checkview -screenshot -2d -path ${imagedir}/${test_image}.png
index 0676fbd..0cf1d58 100644 (file)
@@ -1,5 +1,6 @@
-puts "TODO OCC23748 ALL: Faulty shapes in variables faulty_1 to faulty_"
-puts "TODO OCC23748 ALL: Error : The volume of result shape is"
+puts "TODO OCC23748 ALL: ERROR. offsetperform operation not done."
+puts "TODO OCC23748 ALL: Error: The command cannot be built"
+puts "TODO OCC23748 ALL: Error : The offset cannot be built."
 psphere s 15 270
 
 OFFSETSHAPE 1 {s_2} $calcul $type