diff --git a/src/IntPatch/IntPatch_ImpImpIntersection_4.gxx b/src/IntPatch/IntPatch_ImpImpIntersection_4.gxx index f35ad6b985..705840d027 100644 --- a/src/IntPatch/IntPatch_ImpImpIntersection_4.gxx +++ b/src/IntPatch/IntPatch_ImpImpIntersection_4.gxx @@ -14,6 +14,8 @@ // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. +#include +#include #include #include #include @@ -82,8 +84,6 @@ static inline void MinMax(Standard_Real& theParMIN, Standard_Real& theParMAX) static void VBoundaryPrecise( const math_Matrix& theMatr, const Standard_Real theV1AfterDecrByDelta, const Standard_Real theV2AfterDecrByDelta, - const Standard_Real theV1f, - const Standard_Real theV2f, Standard_Real& theV1Set, Standard_Real& theV2Set) { @@ -108,12 +108,12 @@ static void VBoundaryPrecise( const math_Matrix& theMatr, if(aDet*aDet1 > 0.0) { - theV1Set = Max(theV1AfterDecrByDelta, theV1f); + theV1Set = theV1AfterDecrByDelta; } if(aDet*aDet2 > 0.0) { - theV2Set = Max(theV2AfterDecrByDelta, theV2f); + theV2Set = theV2AfterDecrByDelta; } } @@ -160,15 +160,25 @@ static Standard_Boolean StepComputing(const math_Matrix& theMatr, const Standard_Real theV2Cur, const Standard_Real theDeltaV1, const Standard_Real theDeltaV2, - const Standard_Real theV1f, - const Standard_Real theV1l, - const Standard_Real theV2f, - const Standard_Real theV2l, Standard_Real& theDeltaU1Found/*, Standard_Real& theDeltaU2Found, Standard_Real& theV1Found, Standard_Real& theV2Found*/) { +#ifdef OCCT_DEBUG + bool flShow = false; + + if(flShow) + { + printf("{%+10.20f*V1 + %+10.20f*V2 + %+10.20f*dU1 + %+10.20f*dU2 = %+10.20f\n", + theMatr(1,1), theMatr(1,2), theMatr(1,3), theMatr(1,4), theMatr(1,5)); + printf("{%+10.20f*V1 + %+10.20f*V2 + %+10.20f*dU1 + %+10.20f*dU2 = %+10.20f\n", + theMatr(2,1), theMatr(2,2), theMatr(2,3), theMatr(2,4), theMatr(2,5)); + printf("{%+10.20f*V1 + %+10.20f*V2 + %+10.20f*dU1 + %+10.20f*dU2 = %+10.20f\n", + theMatr(3,1), theMatr(3,2), theMatr(3,3), theMatr(3,4), theMatr(3,5)); + } +#endif + Standard_Boolean isSuccess = Standard_False; theDeltaU1Found/* = theDeltaU2Found*/ = RealLast(); //theV1Found = theV1set; @@ -180,12 +190,12 @@ static Standard_Boolean StepComputing(const math_Matrix& theMatr, //By default, increasing V1(U1) and V2(U1) functions is //considered - Standard_Real aV1Set = Min(theV1Cur + theDeltaV1, theV1l), - aV2Set = Min(theV2Cur + theDeltaV2, theV2l); + Standard_Real aV1Set = theV1Cur + theDeltaV1, + aV2Set = theV2Cur + theDeltaV2; - //However, what is indead? - VBoundaryPrecise( theMatr, theV1Cur - theDeltaV1, theV2Cur - theDeltaV2, - theV1f, theV2f, aV1Set, aV2Set); + //However, what is indeed? + VBoundaryPrecise( theMatr, theV1Cur - theDeltaV1, + theV2Cur - theDeltaV2, aV1Set, aV2Set); aSyst.SetCol(2, theMatr.Col(3)); aSyst.SetCol(3, theMatr.Col(4)); @@ -1213,37 +1223,81 @@ static Standard_Boolean CylCylMonotonicity( const Standard_Real theU1par, return Standard_True; } +//======================================================================= +//function : CylCylComputeParameters +//purpose : Computes U2 (U-parameter of the 2nd cylinder) and, if theDelta != 0, +// esimates the tolerance of U2-computing (estimation result is +// assigned to *theDelta value). +//======================================================================= static Standard_Boolean CylCylComputeParameters(const Standard_Real theU1par, const Standard_Integer theWLIndex, const stCoeffsValue& theCoeffs, - Standard_Real& theU2) + Standard_Real& theU2, + Standard_Real* const theDelta = 0) { - Standard_Real aSign = 0.0; + //This formula is got from some experience and can be changed. + const Standard_Real aTol0 = Min(10.0*Epsilon(1.0)*theCoeffs.mB, aNulValue); + const Standard_Real aTol = 1.0 - aTol0; - switch(theWLIndex) - { - case 0: - aSign = 1.0; - break; - case 1: - aSign = -1.0; - break; - default: - //Standard_Failure::Raise("Error. Range Error!!!!"); + if(theWLIndex < 0 || theWLIndex > 1) return Standard_False; + + const Standard_Real aSign = theWLIndex ? -1.0 : 1.0; + + Standard_Real anArg = cos(theU1par - theCoeffs.mFI1); + anArg = theCoeffs.mB*anArg + theCoeffs.mC; + + if(anArg > aTol) + { + if(theDelta) + *theDelta = 0.0; + + anArg = 1.0; + } + else if(anArg < -aTol) + { + if(theDelta) + *theDelta = 0.0; + + anArg = -1.0; + } + else if(theDelta) + { + //There is a case, when + // const double aPar = 0.99999999999721167; + // const double aFI2 = 2.3593296083566181e-006; + + //Then + // aPar - cos(aFI2) == -5.10703e-015 ==> cos(aFI2) == aPar. + //Theoreticaly, in this case + // aFI2 == +/- acos(aPar). + //However, + // acos(aPar) - aFI2 == 2.16362e-009. + //Error is quite big. + + //This error should be estimated. Let use following way, which is based + //on expanding to Taylor series. + + // acos(p)-acos(p+x) = x/sqrt(1-p*p). + + //If p == (1-d) (when p > 0) or p == (-1+d) (when p < 0) then + // acos(p)-acos(p+x) = x/sqrt(d*(2-d)). + + //Here always aTol0 <= d <= 1. Max(x) is considered (!) to be equal to aTol0. + //In this case + // 8*aTol0 <= acos(p)-acos(p+x) <= sqrt(2/(2-aTol0)-1), + // because 0 < aTol0 < 1. + //E.g. when aTol0 = 1.0e-11, + // 8.0e-11 <= acos(p)-acos(p+x) < 2.24e-6. + + const Standard_Real aDelta = Min(1.0-anArg, 1.0+anArg); + Standard_DivideByZero_Raise_if((aDelta*aDelta < RealSmall()) || (aDelta >= 2.0), + "IntPatch_ImpImpIntersection_4.gxx, CylCylComputeParameters()"); + *theDelta = aTol0/sqrt(aDelta*(2.0-aDelta)); } - Standard_Real anArg = theCoeffs.mB * - cos(theU1par - theCoeffs.mFI1) + - theCoeffs.mC; - - if(aNulValue > 1.0 - anArg) - anArg = 1.0; - - if(anArg + 1.0 < aNulValue) - anArg = -1.0; - - theU2 = theCoeffs.mFI2 + aSign*acos(anArg); + theU2 = acos(anArg); + theU2 = theCoeffs.mFI2 + aSign*theU2; return Standard_True; } @@ -1436,6 +1490,11 @@ Standard_Boolean InscribePoint( const Standard_Real theUfTarget, const Standard_Real thePeriod, const Standard_Boolean theFlForce) { + if(Precision::IsInfinite(theUGiven)) + { + return Standard_False; + } + if((theUfTarget - theUGiven <= theTol2D) && (theUGiven - theUlTarget <= theTol2D)) {//it has already inscribed @@ -1471,6 +1530,9 @@ Standard_Boolean InscribePoint( const Standard_Real theUfTarget, return Standard_False; } + //Make theUGiven nearer to theUfTarget (in order to avoid + //excess iterations) + theUGiven += thePeriod*Floor((theUfTarget-theUGiven)/thePeriod); Standard_Real aDU = theUGiven - theUfTarget; if(aDU > 0.0) @@ -1478,12 +1540,15 @@ Standard_Boolean InscribePoint( const Standard_Real theUfTarget, else aDU = +thePeriod; - while(((theUGiven - theUfTarget)*aDU < 0.0) && !((theUfTarget - theUGiven <= theTol2D) && (theUGiven - theUlTarget <= theTol2D))) + while(((theUGiven - theUfTarget)*aDU < 0.0) && + !((theUfTarget - theUGiven <= theTol2D) && + (theUGiven - theUlTarget <= theTol2D))) { theUGiven += aDU; } - return ((theUfTarget - theUGiven <= theTol2D) && (theUGiven - theUlTarget <= theTol2D)); + return ((theUfTarget - theUGiven <= theTol2D) && + (theUGiven - theUlTarget <= theTol2D)); } //======================================================================= @@ -1524,41 +1589,44 @@ static Standard_Boolean InscribeInterval(const Standard_Real theUfTarget, } //======================================================================= -//function : InscribeAndSortArray -//purpose : Sort from Min to Max value +//function : ExcludeNearElements +//purpose : Checks if theArr contains two almost equal elements. +// If it is true then one of equal elements will be excluded +// (made infinite). +// Returns TRUE if at least one element of theArr has been changed. +//ATTENTION!!! +// 1. Every not infinite element of theArr is considered to be +// in [0, T] interval (where T is the period); +// 2. theArr must be sorted in ascending order. //======================================================================= -static void InscribeAndSortArray( Standard_Real theArr[], - const Standard_Integer theNOfMembers, - const Standard_Real theUf, - const Standard_Real theUl, - const Standard_Real theTol2D, - const Standard_Real thePeriod) +static Standard_Boolean ExcludeNearElements(Standard_Real theArr[], + const Standard_Integer theNOfMembers, + const Standard_Real theTol) { - for(Standard_Integer i = 0; i < theNOfMembers; i++) + Standard_Boolean aRetVal = Standard_False; + for(Standard_Integer i = 1; i < theNOfMembers; i++) { - if(Precision::IsInfinite(theArr[i])) + Standard_Real &anA = theArr[i], + &anB = theArr[i-1]; + + //Here, anA >= anB + + if(Precision::IsInfinite(anA)) + break; + + if((anA-anB) < theTol) { - if(theArr[i] < 0.0) - theArr[i] = -theArr[i]; + anA = (anA + anB)/2.0; - continue; - } - - InscribePoint(theUf, theUl, theArr[i], theTol2D, thePeriod, Standard_False); - - for(Standard_Integer j = i - 1; j >= 0; j--) - { - - if(theArr[j+1] < theArr[j]) - { - Standard_Real anUtemp = theArr[j+1]; - theArr[j+1] = theArr[j]; - theArr[j] = anUtemp; - } + //Make this element infinite an forget it + //(we will not use it in next iterations). + anB = Precision::Infinite(); + aRetVal = Standard_True; } } -} + return aRetVal; +} //======================================================================= //function : AddPointIntoWL @@ -1768,9 +1836,12 @@ static Standard_Boolean AddBoundaryPoint( const IntSurf_Quadric& theQuad1, if(!isTheFound1 && !isTheFound2) return Standard_True; + //We increase U1 parameter. Therefore, added point must have U1 parameter less than + //or equal to current (conditions "(anUpar1 < theU1)" and "(anUpar2 < theU1)"). + if(anUpar1 < anUpar2) { - if(isTheFound1) + if(isTheFound1 && (anUpar1 < theU1)) { Standard_Real aU2 = theU2, aV1 = theV1, aV2 = theV2; if(!CylCylComputeParameters(anUpar1, theWLIndex, theCoeffs, aU2, aV1, aV2)) @@ -1794,8 +1865,12 @@ static Standard_Boolean AddBoundaryPoint( const IntSurf_Quadric& theQuad1, isTheFound1 = Standard_False; } } + else + { + isTheFound1 = Standard_False; + } - if(isTheFound2) + if(isTheFound2 && (anUpar2 < theU1)) { Standard_Real aU2 = theU2, aV1 = theV1, aV2 = theV2; if(!CylCylComputeParameters(anUpar2, theWLIndex, theCoeffs, aU2, aV1, aV2)) @@ -1819,10 +1894,14 @@ static Standard_Boolean AddBoundaryPoint( const IntSurf_Quadric& theQuad1, isTheFound2 = Standard_False; } } + else + { + isTheFound2 = Standard_False; + } } else { - if(isTheFound2) + if(isTheFound2 && (anUpar2 < theU1)) { Standard_Real aU2 = theU2, aV1 = theV1, aV2 = theV2; if(!CylCylComputeParameters(anUpar2, theWLIndex, theCoeffs, aU2, aV1, aV2)) @@ -1846,8 +1925,12 @@ static Standard_Boolean AddBoundaryPoint( const IntSurf_Quadric& theQuad1, isTheFound2 = Standard_False; } } + else + { + isTheFound2 = Standard_False; + } - if(isTheFound1) + if(isTheFound1 && (anUpar1 < theU1)) { Standard_Real aU2 = theU2, aV1 = theV1, aV2 = theV2; if(!CylCylComputeParameters(anUpar1, theWLIndex, theCoeffs, aU2, aV1, aV2)) @@ -1871,6 +1954,10 @@ static Standard_Boolean AddBoundaryPoint( const IntSurf_Quadric& theQuad1, isTheFound1 = Standard_False; } } + else + { + isTheFound1 = Standard_False; + } } return Standard_True; @@ -2001,7 +2088,7 @@ static void SeekAdditionalPoints( const IntSurf_Quadric& theQuad1, //======================================================================= //function : CriticalPointsComputing -//purpose : +//purpose : theNbCritPointsMax contains true number of critical points //======================================================================= static void CriticalPointsComputing(const stCoeffsValue& theCoeffs, const Standard_Real theUSurf1f, @@ -2010,9 +2097,19 @@ static void CriticalPointsComputing(const stCoeffsValue& theCoeffs, const Standard_Real theUSurf2l, const Standard_Real thePeriod, const Standard_Real theTol2D, - const Standard_Integer theNbCritPointsMax, + Standard_Integer& theNbCritPointsMax, Standard_Real theU1crit[]) { + //[0...1] - in these points parameter U1 goes through + // the seam-edge of the first cylinder. + //[2...3] - First and last U1 parameter. + //[4...5] - in these points parameter U2 goes through + // the seam-edge of the second cylinder. + //[6...9] - in these points an intersection line goes through + // U-boundaries of the second surface. + + theNbCritPointsMax = 10; + theU1crit[0] = 0.0; theU1crit[1] = thePeriod; theU1crit[2] = theUSurf1f; @@ -2029,31 +2126,86 @@ static void CriticalPointsComputing(const stCoeffsValue& theCoeffs, anArg = -1.0; theU1crit[4] = -acos(anArg) + theCoeffs.mFI1; - theU1crit[5] = acos(anArg) + theCoeffs.mFI1; + theU1crit[5] = acos(anArg) + theCoeffs.mFI1; } Standard_Real aSf = cos(theUSurf2f - theCoeffs.mFI2); Standard_Real aSl = cos(theUSurf2l - theCoeffs.mFI2); MinMax(aSf, aSl); - theU1crit[6] = Abs((aSl - theCoeffs.mC) / theCoeffs.mB) < 1.0 ? -acos((aSl - theCoeffs.mC) / theCoeffs.mB) + theCoeffs.mFI1 : -Precision::Infinite(); - theU1crit[7] = Abs((aSf - theCoeffs.mC) / theCoeffs.mB) < 1.0 ? -acos((aSf - theCoeffs.mC) / theCoeffs.mB) + theCoeffs.mFI1 : Precision::Infinite(); - theU1crit[8] = Abs((aSf - theCoeffs.mC) / theCoeffs.mB) < 1.0 ? acos((aSf - theCoeffs.mC) / theCoeffs.mB) + theCoeffs.mFI1 : -Precision::Infinite(); - theU1crit[9] = Abs((aSl - theCoeffs.mC) / theCoeffs.mB) < 1.0 ? acos((aSl - theCoeffs.mC) / theCoeffs.mB) + theCoeffs.mFI1 : Precision::Infinite(); + //In accorance with pure mathematic, theU1crit[6] and [8] + //must be -Precision::Infinite() instead of used +Precision::Infinite() + theU1crit[6] = Abs((aSl - theCoeffs.mC) / theCoeffs.mB) < 1.0 ? + -acos((aSl - theCoeffs.mC) / theCoeffs.mB) + theCoeffs.mFI1 : + Precision::Infinite(); + theU1crit[7] = Abs((aSf - theCoeffs.mC) / theCoeffs.mB) < 1.0 ? + -acos((aSf - theCoeffs.mC) / theCoeffs.mB) + theCoeffs.mFI1 : + Precision::Infinite(); + theU1crit[8] = Abs((aSf - theCoeffs.mC) / theCoeffs.mB) < 1.0 ? + acos((aSf - theCoeffs.mC) / theCoeffs.mB) + theCoeffs.mFI1 : + Precision::Infinite(); + theU1crit[9] = Abs((aSl - theCoeffs.mC) / theCoeffs.mB) < 1.0 ? + acos((aSl - theCoeffs.mC) / theCoeffs.mB) + theCoeffs.mFI1 : + Precision::Infinite(); - //preparative treatment of array - InscribeAndSortArray(theU1crit, theNbCritPointsMax, 0.0, thePeriod, theTol2D, thePeriod); - for(Standard_Integer i = 1; i < theNbCritPointsMax; i++) + //preparative treatment of array. This array must have faled to contain negative + //infinity number + + for(Standard_Integer i = 0; i < theNbCritPointsMax; i++) { - Standard_Real &a = theU1crit[i], - &b = theU1crit[i-1]; - const Standard_Real aRemain = fmod(Abs(a - b), thePeriod); // >= 0, because Abs(a - b) >= 0 - if((Abs(a - b) < theTol2D) || (aRemain < theTol2D) || (Abs(aRemain - thePeriod) < theTol2D)) + if(Precision::IsInfinite(theU1crit[i])) { - a = (a + b)/2.0; - b = Precision::Infinite(); + continue; } + + theU1crit[i] = fmod(theU1crit[i], thePeriod); + if(theU1crit[i] < 0.0) + theU1crit[i] += thePeriod; } + + //Here all not infinite elements of theU1crit are in [0, thePeriod) range + + do + { + std::sort(theU1crit, theU1crit + theNbCritPointsMax); + } + while(ExcludeNearElements(theU1crit, theNbCritPointsMax, theTol2D)); + + //Here all not infinite elements in theU1crit are different and sorted. + + while(theNbCritPointsMax > 0) + { + Standard_Real &anB = theU1crit[theNbCritPointsMax-1]; + if(Precision::IsInfinite(anB)) + { + theNbCritPointsMax--; + continue; + } + + //1st not infinte element is found + + if(theNbCritPointsMax == 1) + break; + + //Here theNbCritPointsMax > 1 + + Standard_Real &anA = theU1crit[0]; + + //Compare 1st and last significant elements of theU1crit + //They may still differs by period. + + if (Abs(anB - anA - thePeriod) < theTol2D) + {//E.g. anA == 2.0e-17, anB == (thePeriod-1.0e-18) + anA = (anA + anB - thePeriod)/2.0; + anB = Precision::Infinite(); + theNbCritPointsMax--; + } + + //Out of "while(theNbCritPointsMax > 0)" cycle. + break; + } + + //Attention! Here theU1crit may be unsorted. } //======================================================================= @@ -2110,7 +2262,10 @@ Standard_Boolean IntCyCyTrim( const IntSurf_Quadric& theQuad1, RealToInt(20.0*aCyl1.Radius())), aNbMaxPoints); const Standard_Real aPeriod = 2.0*M_PI; const Standard_Real aStepMin = theTol2D, - aStepMax = (aUSurf1l-aUSurf1f)/IntToReal(aNbPoints); + aStepMax = (aUSurf1l-aUSurf1f > M_PI/100.0) ? + (aUSurf1l-aUSurf1f)/IntToReal(aNbPoints) : + aUSurf1l-aUSurf1f; + const Standard_Integer aNbWLines = 2; const stCoeffsValue anEquationCoeffs(aCyl1, aCyl2); @@ -2289,13 +2444,6 @@ Standard_Boolean IntCyCyTrim( const IntSurf_Quadric& theQuad1, } //Critical points - //[0...1] - in these points parameter U1 goes through - // the seam-edge of the first cylinder. - //[2...3] - First and last U1 parameter. - //[4...5] - in these points parameter U2 goes through - // the seam-edge of the second cylinder. - //[6...9] - in these points an intersection line goes through - // U-boundaries of the second surface. const Standard_Integer aNbCritPointsMax = 10; Standard_Real anU1crit[aNbCritPointsMax] = {Precision::Infinite(), Precision::Infinite(), @@ -2308,9 +2456,9 @@ Standard_Boolean IntCyCyTrim( const IntSurf_Quadric& theQuad1, Precision::Infinite(), Precision::Infinite()}; + Standard_Integer aNbCritPoints = aNbCritPointsMax; CriticalPointsComputing(anEquationCoeffs, aUSurf1f, aUSurf1l, aUSurf2f, aUSurf2l, - aPeriod, theTol2D, aNbCritPointsMax, anU1crit); - + aPeriod, theTol2D, aNbCritPoints, anU1crit); //Getting Walking-line @@ -2334,7 +2482,12 @@ Standard_Boolean IntCyCyTrim( const IntSurf_Quadric& theQuad1, const Standard_Boolean isDeltaPeriod = IsEqual(anUl-anUf, aPeriod); //Inscribe and sort critical points - InscribeAndSortArray(anU1crit, aNbCritPointsMax, anUf, anUl, theTol2D, aPeriod); + for(Standard_Integer i = 0; i < aNbCritPoints; i++) + { + InscribePoint(anUf, anUl, anU1crit[i], theTol2D, aPeriod, Standard_False); + } + + std::sort(anU1crit, anU1crit + aNbCritPoints); while(anUf < anUl) { @@ -2357,17 +2510,20 @@ Standard_Boolean IntCyCyTrim( const IntSurf_Quadric& theQuad1, anUexpect[i] = anUf; } - Standard_Real anU1 = anUf; - Standard_Real aCriticalDelta[aNbCritPointsMax]; - for(Standard_Integer i = 0; i < aNbCritPointsMax; i++) - aCriticalDelta[i] = anU1 - anU1crit[i]; + for(Standard_Integer aCritPID = 0; aCritPID < aNbCritPoints; aCritPID++) + { //We are not intersted in elements of aCriticalDelta array + //if their index is greater than or equal to aNbCritPoints + aCriticalDelta[aCritPID] = anUf - anU1crit[aCritPID]; + } + + Standard_Real anU1 = anUf; Standard_Boolean isFirst = Standard_True; while(anU1 <= anUl) { - for(Standard_Integer i = 0; i < aNbCritPointsMax; i++) + for(Standard_Integer i = 0; i < aNbCritPoints; i++) { if((anU1 - anU1crit[i])*aCriticalDelta[i] < 0.0) { @@ -2392,7 +2548,7 @@ Standard_Boolean IntCyCyTrim( const IntSurf_Quadric& theQuad1, if(isDeltaPeriod) { - //if isAddedIntoWL* == TRUE WLine contains only one point + //if isAddedIntoWL[i] == TRUE WLine contains only one point //(which was end point of previous WLine). If we will //add point found on the current step WLine will contain only //two points. At that both these points will be equal to the @@ -2422,11 +2578,33 @@ Standard_Boolean IntCyCyTrim( const IntSurf_Quadric& theQuad1, { const Standard_Integer aNbPntsWL = aWLine[i].IsNull() ? 0 : aWLine[i]->Curve()->NbPoints(); + + if( (aWLFindStatus[i] == WLFStatus_Broken) || + (aWLFindStatus[i] == WLFStatus_Absent)) + {//Begin and end of WLine must be on boundary point + //or on seam-edge strictly (if it is possible). - CylCylComputeParameters(anU1, i, anEquationCoeffs, aU2[i]); + Standard_Real aTol = theTol2D; + CylCylComputeParameters(anU1, i, anEquationCoeffs, aU2[i], &aTol); + InscribePoint(aUSurf2f, aUSurf2l, aU2[i], theTol2D, aPeriod, Standard_False); - InscribePoint(aUSurf2f, aUSurf2l, aU2[i], theTol2D, aPeriod, Standard_False); + aTol = Max(aTol, theTol2D); + if(Abs(aU2[i]) <= aTol) + aU2[i] = 0.0; + else if(Abs(aU2[i] - aPeriod) <= aTol) + aU2[i] = aPeriod; + else if(Abs(aU2[i] - aUSurf2f) <= aTol) + aU2[i] = aUSurf2f; + else if(Abs(aU2[i] - aUSurf2l) <= aTol) + aU2[i] = aUSurf2l; + } + else + { + CylCylComputeParameters(anU1, i, anEquationCoeffs, aU2[i]); + InscribePoint(aUSurf2f, aUSurf2l, aU2[i], theTol2D, aPeriod, Standard_False); + } + if(aNbPntsWL == 0) {//the line has not contained any points yet if(((aUSurf2f + aPeriod - aUSurf2l) <= 2.0*theTol2D) && @@ -2477,20 +2655,6 @@ Standard_Boolean IntCyCyTrim( const IntSurf_Quadric& theQuad1, } } - if( (aWLFindStatus[i] == WLFStatus_Broken) || - (aWLFindStatus[i] == WLFStatus_Absent)) - {//Begin and end of WLine must be on boundary point - //or on seam-edge strictly (if it is possible). - if(Abs(aU2[i]) <= theTol2D) - aU2[i] = 0.0; - else if(Abs(aU2[i] - aPeriod) <= theTol2D) - aU2[i] = aPeriod; - else if(Abs(aU2[i] - aUSurf2f) <= theTol2D) - aU2[i] = aUSurf2f; - else if(Abs(aU2[i] - aUSurf2l) <= theTol2D) - aU2[i] = aUSurf2l; - } - CylCylComputeParameters(anU1, aU2[i], anEquationCoeffs, aV1[i], aV2[i]); if(isFirst) @@ -2530,9 +2694,6 @@ Standard_Boolean IntCyCyTrim( const IntSurf_Quadric& theQuad1, isBoundIntersect = Standard_True; } - aV1Prev[i] = aV1[i]; - aV2Prev[i] = aV2[i]; - if(aWLFindStatus[i] == WLFStatus_Broken) isBroken = Standard_True; @@ -2587,6 +2748,10 @@ Standard_Boolean IntCyCyTrim( const IntSurf_Quadric& theQuad1, (Abs(aV2Prev[i] - aVSurf2f) <= theTol2D) || (Abs(aV2Prev[i] - aVSurf2l) <= theTol2D)); + + aV1Prev[i] = aV1[i]; + aV2Prev[i] = aV2[i]; + if((aWLFindStatus[i] == WLFStatus_Exist) && (isFound1 || isFound2) && !isPrevVBound) { aWLFindStatus[i] = WLFStatus_Broken; //start a new line @@ -2651,9 +2816,6 @@ Standard_Boolean IntCyCyTrim( const IntSurf_Quadric& theQuad1, } } - aV1Prev[i] = aV1[i]; - aV2Prev[i] = aV2[i]; - if(aWLFindStatus[i] == WLFStatus_Broken) isBroken = Standard_True; }//for(Standard_Integer i = 0; i < aNbWLines; i++) @@ -2723,15 +2885,29 @@ Standard_Boolean IntCyCyTrim( const IntSurf_Quadric& theQuad1, if(!isAdded) { Standard_Real anUmaxAdded = RealFirst(); - for(Standard_Integer i = 0; i < aNbWLines; i++) + { - Standard_Real aU1c = 0.0, aV1c = 0.0; - if(isTheReverse) - aWLine[i]->Curve()->Value(aWLine[i]->NbPnts()).ParametersOnS2(aU1c, aV1c); - else - aWLine[i]->Curve()->Value(aWLine[i]->NbPnts()).ParametersOnS1(aU1c, aV1c); + Standard_Boolean isChanged = Standard_False; + for(Standard_Integer i = 0; i < aNbWLines; i++) + { + if(aWLFindStatus[i] == WLFStatus_Absent) + continue; - anUmaxAdded = Max(anUmaxAdded, aU1c); + Standard_Real aU1c = 0.0, aV1c = 0.0; + if(isTheReverse) + aWLine[i]->Curve()->Value(aWLine[i]->NbPnts()).ParametersOnS2(aU1c, aV1c); + else + aWLine[i]->Curve()->Value(aWLine[i]->NbPnts()).ParametersOnS1(aU1c, aV1c); + + anUmaxAdded = Max(anUmaxAdded, aU1c); + isChanged = Standard_True; + } + + if(!isChanged) + { //If anUmaxAdded were not changed in previous cycle then + //we would break existing WLines. + break; + } } for(Standard_Integer i = 0; i < aNbWLines; i++) @@ -2794,7 +2970,7 @@ Standard_Boolean IntCyCyTrim( const IntSurf_Quadric& theQuad1, anEquationCoeffs.mVecA2*aCosU2 + anEquationCoeffs.mVecB2*aSinU2 + anEquationCoeffs.mVecD); - if(!StepComputing(aMatr, aV1[i], aV2[i], aDeltaV1, aDeltaV2, aVSurf1f, aVSurf1l, aVSurf2f, aVSurf2l, aStepTmp)) + if(!StepComputing(aMatr, aV1[i], aV2[i], aDeltaV1, aDeltaV2, aStepTmp)) { //To avoid cycling-up anUexpect[i] += aStepMax; @@ -2887,8 +3063,8 @@ Standard_Boolean IntCyCyTrim( const IntSurf_Quadric& theQuad1, } -//Delete the points in theSPnt, which -//lie at least in one of the line in theSlin. + //Delete the points in theSPnt, which + //lie at least in one of the line in theSlin. for(Standard_Integer aNbPnt = 1; aNbPnt <= theSPnt.Length(); aNbPnt++) { for(Standard_Integer aNbLin = 1; aNbLin <= theSlin.Length(); aNbLin++) diff --git a/src/IntPatch/IntPatch_Intersection.cxx b/src/IntPatch/IntPatch_Intersection.cxx index c9cfb0602c..0dec3febdd 100644 --- a/src/IntPatch/IntPatch_Intersection.cxx +++ b/src/IntPatch/IntPatch_Intersection.cxx @@ -37,11 +37,88 @@ static const Standard_Integer aNbPointsInALine = 200; //======================================================================= -//function : IsSeamOrBound -//purpose : Returns TRUE if point thePt1 lies in seam-edge -// (if it exists) or surface boundaries; +//function : MinMax +//purpose : Replaces theParMIN = MIN(theParMIN, theParMAX), +// theParMAX = MAX(theParMIN, theParMAX). //======================================================================= -static Standard_Boolean IsSeamOrBound(const IntSurf_PntOn2S& thePt1, +static inline void MinMax(Standard_Real& theParMIN, Standard_Real& theParMAX) +{ + if(theParMIN > theParMAX) + { + const Standard_Real aTmp = theParMAX; + theParMAX = theParMIN; + theParMIN = aTmp; + } +} + +//======================================================================= +//function : IsSeam +//purpose : Returns: +// 0 - if interval [theU1, theU2] does not intersect the "seam-edge" +// or if "seam-edge" do not exist; +// 1 - if interval (theU1, theU2) intersect the "seam-edge". +// 2 - if theU1 or/and theU2 lie ON the "seam-edge" +// +//ATTENTION!!! +// If (theU1 == theU2) then this function will return only both 0 or 2. +//======================================================================= +static Standard_Integer IsSeam( const Standard_Real theU1, + const Standard_Real theU2, + const Standard_Real thePeriod) +{ + if(IsEqual(thePeriod, 0.0)) + return 0; + + //If interval [theU1, theU2] intersect seam-edge then there exists an integer + //number N such as + // (theU1 <= T*N <= theU2) <=> (theU1/T <= N <= theU2/T), + //where T is the period. + //I.e. the inerval [theU1/T, theU2/T] must contain at least one + //integer number. In this case, Floor(theU1/T) and Floor(theU2/T) + //return different values or theU1/T is strictly integer number. + //Examples: + // 1. theU1/T==2.8, theU2/T==3.5 => Floor(theU1/T) == 2, Floor(theU2/T) == 3. + // 2. theU1/T==2.0, theU2/T==2.6 => Floor(theU1/T) == Floor(theU2/T) == 2. + + const Standard_Real aVal1 = theU1/thePeriod, + aVal2 = theU2/thePeriod; + const Standard_Integer aPar1 = static_cast(Floor(aVal1)); + const Standard_Integer aPar2 = static_cast(Floor(aVal2)); + if(aPar1 != aPar2) + {//Interval (theU1, theU2] intersects seam-edge + if(IsEqual(aVal2, static_cast(aPar2))) + {//aVal2 is an integer number => theU2 lies ON the "seam-edge" + return 2; + } + + return 1; + } + + //Here, aPar1 == aPar2. + + if(IsEqual(aVal1, static_cast(aPar1))) + {//aVal1 is an integer number => theU1 lies ON the "seam-edge" + return 2; + } + + //If aVal2 is a true integer number then always (aPar1 != aPar2). + + return 0; +} + +//======================================================================= +//function : IsSeamOrBound +//purpose : Returns TRUE if segment [thePtf, thePtl] intersects "seam-edge" +// (if it exist) or surface boundaries and both thePtf and thePtl do +// not match "seam-edge" or boundaries. +// Point thePtmid lies in this segment. If thePtmid match +// "seam-edge" or boundaries strictly (without any tolerance) then +// the function will return TRUE. +// See comments in function body for detail information. +//======================================================================= +static Standard_Boolean IsSeamOrBound(const IntSurf_PntOn2S& thePtf, + const IntSurf_PntOn2S& thePtl, + const IntSurf_PntOn2S& thePtmid, const Standard_Real theU1Period, const Standard_Real theU2Period, const Standard_Real theV1Period, @@ -56,26 +133,112 @@ static Standard_Boolean IsSeamOrBound(const IntSurf_PntOn2S& thePt1, const Standard_Real theVlSurf2) { Standard_Real aU11 = 0.0, aU12 = 0.0, aV11 = 0.0, aV12 = 0.0; - thePt1.Parameters(aU11, aV11, aU12, aV12); + Standard_Real aU21 = 0.0, aU22 = 0.0, aV21 = 0.0, aV22 = 0.0; + thePtf.Parameters(aU11, aV11, aU12, aV12); + thePtl.Parameters(aU21, aV21, aU22, aV22); - Standard_Boolean aCond = Standard_False; - aCond = aCond || (!IsEqual(theU1Period, 0.0) && - IsEqual(fmod(aU11, theU1Period), 0.0)); + MinMax(aU11, aU21); + MinMax(aV11, aV21); + MinMax(aU12, aU22); + MinMax(aV12, aV22); - aCond = aCond || (!IsEqual(theU2Period, 0.0) && - IsEqual(fmod(aU12, theU2Period), 0.0)); + if((aU11 - theUfSurf1)*(aU21 - theUfSurf1) < 0.0) + {//Interval [aU11, aU21] intersects theUfSurf1 + return Standard_True; + } - aCond = aCond || (!IsEqual(theV1Period, 0.0) && - IsEqual(fmod(aV11, theV1Period), 0.0)); + if((aU11 - theUlSurf1)*(aU21 - theUlSurf1) < 0.0) + {//Interval [aU11, aU21] intersects theUlSurf1 + return Standard_True; + } - aCond = aCond || (!IsEqual(theV2Period, 0.0) && - IsEqual(fmod(aV12, theV2Period), 0.0)); + if((aV11 - theVfSurf1)*(aV21 - theVfSurf1) < 0.0) + {//Interval [aV11, aV21] intersects theVfSurf1 + return Standard_True; + } - return aCond || - IsEqual(aU11, theUfSurf1) || IsEqual(aU11, theUlSurf1) || - IsEqual(aU12, theUfSurf2) || IsEqual(aU12, theUlSurf2) || - IsEqual(aV11, theVfSurf1) || IsEqual(aV11, theVlSurf1) || - IsEqual(aV12, theVfSurf2) || IsEqual(aV12, theVlSurf2); + if((aV11 - theVlSurf1)*(aV21 - theVlSurf1) < 0.0) + {//Interval [aV11, aV21] intersects theVlSurf1 + return Standard_True; + } + + if((aU12 - theUfSurf2)*(aU22 - theUfSurf2) < 0.0) + {//Interval [aU12, aU22] intersects theUfSurf2 + return Standard_True; + } + + if((aU12 - theUlSurf2)*(aU22 - theUlSurf2) < 0.0) + {//Interval [aU12, aU22] intersects theUlSurf2 + return Standard_True; + } + + if((aV12 - theVfSurf2)*(aV22 - theVfSurf2) < 0.0) + {//Interval [aV12, aV22] intersects theVfSurf2 + return Standard_True; + } + + if((aV12 - theVlSurf2)*(aV22 - theVlSurf2) < 0.0) + {//Interval [aV12, aV22] intersects theVlSurf2 + return Standard_True; + } + + if(IsSeam(aU11, aU21, theU1Period)) + return Standard_True; + + if(IsSeam(aV11, aV21, theV1Period)) + return Standard_True; + + if(IsSeam(aU12, aU22, theU2Period)) + return Standard_True; + + if(IsSeam(aV12, aV22, theV2Period)) + return Standard_True; + + /* + The segment [thePtf, thePtl] does not intersect the boundaries and + the seam-edge of the surfaces. + Nevertheless, following situation is possible: + + seam or + bound + | + thePtf * | + | + * thePtmid + thePtl * | + | + + This case must be processed, too. + */ + + Standard_Real aU1 = 0.0, aU2 = 0.0, aV1 = 0.0, aV2 = 0.0; + thePtmid.Parameters(aU1, aV1, aU2, aV2); + + if(IsEqual(aU1, theUfSurf1) || IsEqual(aU1, theUlSurf1)) + return Standard_True; + + if(IsEqual(aU2, theUfSurf2) || IsEqual(aU2, theUlSurf2)) + return Standard_True; + + if(IsEqual(aV1, theVfSurf1) || IsEqual(aV1, theVlSurf1)) + return Standard_True; + + if(IsEqual(aV2, theVfSurf2) || IsEqual(aV2, theVlSurf2)) + return Standard_True; + + if(IsSeam(aU1, aU1, theU1Period)) + return Standard_True; + + if(IsSeam(aU2, aU2, theU2Period)) + return Standard_True; + + if(IsSeam(aV1, aV1, theV1Period)) + return Standard_True; + + if(IsSeam(aV2, aV2, theV2Period)) + return Standard_True; + + return Standard_False; } //======================================================================= @@ -139,7 +302,6 @@ static void JoinWLines(IntPatch_SequenceOfLine& theSlin, { Handle(IntPatch_WLine) aWLine2 (Handle(IntPatch_WLine)::DownCast(theSlin.Value(aNumOfLine2))); - const Standard_Integer aNbPntsWL1 = aWLine1->NbPnts(); const Standard_Integer aNbPntsWL2 = aWLine2->NbPnts(); const IntSurf_PntOn2S& aPntFWL1 = aWLine1->Point(1); @@ -150,7 +312,9 @@ static void JoinWLines(IntPatch_SequenceOfLine& theSlin, if(aPntFWL1.IsSame(aPntFWL2, Precision::Confusion())) { - if(!IsSeamOrBound(aPntFWL1, theU1Period, theU2Period, + const IntSurf_PntOn2S& aPt1 = aWLine1->Point(2); + const IntSurf_PntOn2S& aPt2 = aWLine2->Point(2); + if(!IsSeamOrBound(aPt1, aPt2, aPntFWL1, theU1Period, theU2Period, theV1Period, theV2Period, theUfSurf1, theUlSurf1, theVfSurf1, theVlSurf1, theUfSurf2, theUlSurf2, theVfSurf2, theVlSurf2)) @@ -174,7 +338,9 @@ static void JoinWLines(IntPatch_SequenceOfLine& theSlin, if(aPntFWL1.IsSame(aPntLWL2, Precision::Confusion())) { - if(!IsSeamOrBound(aPntFWL1, theU1Period, theU2Period, + const IntSurf_PntOn2S& aPt1 = aWLine1->Point(2); + const IntSurf_PntOn2S& aPt2 = aWLine2->Point(aNbPntsWL2-1); + if(!IsSeamOrBound(aPt1, aPt2, aPntFWL1, theU1Period, theU2Period, theV1Period, theV2Period, theUfSurf1, theUlSurf1, theVfSurf1, theVlSurf1, theUfSurf2, theUlSurf2, theVfSurf2, theVlSurf2)) @@ -198,7 +364,9 @@ static void JoinWLines(IntPatch_SequenceOfLine& theSlin, if(aPntLWL1.IsSame(aPntFWL2, Precision::Confusion())) { - if(!IsSeamOrBound(aPntLWL1, theU1Period, theU2Period, + const IntSurf_PntOn2S& aPt1 = aWLine1->Point(aNbPntsWL1-1); + const IntSurf_PntOn2S& aPt2 = aWLine2->Point(2); + if(!IsSeamOrBound(aPt1, aPt2, aPntLWL1, theU1Period, theU2Period, theV1Period, theV2Period, theUfSurf1, theUlSurf1, theVfSurf1, theVlSurf1, theUfSurf2, theUlSurf2, theVfSurf2, theVlSurf2)) @@ -222,7 +390,9 @@ static void JoinWLines(IntPatch_SequenceOfLine& theSlin, if(aPntLWL1.IsSame(aPntLWL2, Precision::Confusion())) { - if(!IsSeamOrBound(aPntLWL1, theU1Period, theU2Period, + const IntSurf_PntOn2S& aPt1 = aWLine1->Point(aNbPntsWL1-1); + const IntSurf_PntOn2S& aPt2 = aWLine2->Point(aNbPntsWL2-1); + if(!IsSeamOrBound(aPt1, aPt2, aPntLWL1, theU1Period, theU2Period, theV1Period, theV2Period, theUfSurf1, theUlSurf1, theVfSurf1, theVlSurf1, theUfSurf2, theUlSurf2, theVfSurf2, theVlSurf2)) diff --git a/src/IntTools/IntTools_FaceFace.cxx b/src/IntTools/IntTools_FaceFace.cxx index 77709c3a8f..7759fdad3a 100644 --- a/src/IntTools/IntTools_FaceFace.cxx +++ b/src/IntTools/IntTools_FaceFace.cxx @@ -644,7 +644,7 @@ void IntTools_FaceFace::Perform(const TopoDS_Face& aF1, { const Standard_Real UVMaxStep = 0.001; const Standard_Real Deflection = (hasCone) ? 0.085 : 0.1; - myIntersector.SetTolerances(TolArc, TolTang, UVMaxStep, Deflection); + myIntersector.SetTolerances(TolArc, TolTang, UVMaxStep, Deflection); } if((myHS1->IsUClosed() && !myHS1->IsUPeriodic()) || @@ -1672,6 +1672,11 @@ Standard_Real IntTools_FaceFace::ComputeTolerance() case IntPatch_Walking:{ Handle(IntPatch_WLine) WL = Handle(IntPatch_WLine)::DownCast(L); + +#ifdef OCCT_DEBUG + //WL->Dump(); +#endif + // Standard_Integer ifprm, ilprm; // diff --git a/tests/bugs/modalg_5/bug24915 b/tests/bugs/modalg_5/bug24915 index b3b6fa6f72..f33a47d3ac 100755 --- a/tests/bugs/modalg_5/bug24915 +++ b/tests/bugs/modalg_5/bug24915 @@ -1,5 +1,4 @@ puts "TODO OCC25929 ALL: Error: Tolerance is too big!" -puts "TODO OCC25929 ALL: Error : T=0.818182" puts "=========" puts "CR24915" puts "=========" diff --git a/tests/bugs/modalg_5/bug25292_11 b/tests/bugs/modalg_5/bug25292_11 index cd6294ed86..1c667efb50 100644 --- a/tests/bugs/modalg_5/bug25292_11 +++ b/tests/bugs/modalg_5/bug25292_11 @@ -29,7 +29,7 @@ set log [bopcurves f1 f2 -2d] regexp {Tolerance Reached=+([-0-9.+eE]+)\n+([-0-9.+eE]+)} ${log} full Toler NbCurv #This value must be equal to the analogical value in bug25292_11 and bug25292_12 of "bugs modalg_5" testgrid. -set MaxTol 1.e-7 +set MaxTol 1.5e-7 #This value must be equal to the analogical value in bug25292_11, bug25292_12, bug25292_15 and bug25292_16 of "bugs modalg_5" testgrid. set GoodNbCurv 4 diff --git a/tests/bugs/modalg_5/bug25292_12 b/tests/bugs/modalg_5/bug25292_12 index f9fdf520ee..dfc8dad4ef 100644 --- a/tests/bugs/modalg_5/bug25292_12 +++ b/tests/bugs/modalg_5/bug25292_12 @@ -29,7 +29,7 @@ set log [bopcurves f2 f1 -2d] regexp {Tolerance Reached=+([-0-9.+eE]+)\n+([-0-9.+eE]+)} ${log} full Toler NbCurv #This value must be equal to the analogical value in bug25292_11 and bug25292_12 of "bugs modalg_5" testgrid. -set MaxTol 1.e-7 +set MaxTol 1.5e-7 #This value must be equal to the analogical value in bug25292_11, bug25292_12, bug25292_15 and bug25292_16 of "bugs modalg_5" testgrid. set GoodNbCurv 4 diff --git a/tests/bugs/modalg_6/bug26310_1 b/tests/bugs/modalg_6/bug26310_1 new file mode 100644 index 0000000000..394cfad094 --- /dev/null +++ b/tests/bugs/modalg_6/bug26310_1 @@ -0,0 +1,44 @@ +puts "========" +puts "OCC26310" +puts "========" +puts "" +################################################# +# Very slow boolean cut operations on cylinders +################################################# + +if { [regexp {Debug mode} [dversion]] } { + set max_time 0.3 +} else { + set max_time 0.15 +} + +set maxToler 1.5e-5 + +restore [locate_data_file OCC26310-b1.brep] b1 +restore [locate_data_file OCC26310-b2.brep] b2 + +explode b1 f +explode b2 f + +dchrono cr reset +dchrono cr start +set log1 [bopcurves b1_1 b2_1 -2d] +dchrono cr stop + +regexp {Tolerance Reached=+([-0-9.+eE]+)} ${log1} full Toler + +puts "TolReached = $Toler" + +if { $Toler > $maxToler } { + puts "Error: Tolerance is too big ($Toler > $maxToler)" +} + +set log2 [dchrono cr show] + +regexp {CPU user time: ([-0-9.+eE]+) seconds} $log2 full sec + +if { $sec > ${max_time} } { + puts "Error: CPU user time is more than ${max_time} seconds" +} else { + puts "OK: CPU user time is less than ${max_time} seconds" +} diff --git a/tests/bugs/modalg_6/bug26310_2 b/tests/bugs/modalg_6/bug26310_2 new file mode 100644 index 0000000000..8ade905886 --- /dev/null +++ b/tests/bugs/modalg_6/bug26310_2 @@ -0,0 +1,26 @@ +puts "========" +puts "OCC26310" +puts "========" +puts "" +################################################# +# Very slow boolean cut operations on cylinders +################################################# + +restore [locate_data_file OCC26310-b1.brep] b1 +restore [locate_data_file OCC26310-b2.brep] b2 + +bsection result b1 b2 + +smallview +donly result + +set log [checksection result] + +if { [string compare -nocase $log " nb alone Vertices : 0\n\n"] } { + puts "ERROR: the section is not closed" +} else { + puts "The section is OK" +} + +fit +set only_screen_axo 1 diff --git a/tests/bugs/modalg_6/bug26310_3 b/tests/bugs/modalg_6/bug26310_3 new file mode 100644 index 0000000000..3879f7ca43 --- /dev/null +++ b/tests/bugs/modalg_6/bug26310_3 @@ -0,0 +1,37 @@ +puts "========" +puts "OCC26310" +puts "========" +puts "" +################################################# +# Very slow boolean cut operations on cylinders +################################################# + +restore [locate_data_file OCC26310-b1.brep] b1 +restore [locate_data_file OCC26310-b2.brep] b2 + +bop b1 b2 + +bopcut res1 +boptuc res2 + +checkshape res1 +checkshape res2 + +set log1 [bopargcheck res1 #F] +set log2 [bopargcheck res2 #F] + +if { [string compare -nocase $log1 "Shape(s) seem(s) to be valid for BOP.\n"] } { + puts "ERROR. res1 is not valid for BOP" +} + +if { [string compare -nocase $log2 "Shape(s) seem(s) to be valid for BOP.\n"] } { + puts "ERROR. res2 is not valid for BOP" +} + +smallview +donly res1 +fit +xwd ${imagedir}/${casename}_1.png +donly res2 +fit +xwd ${imagedir}/${casename}_2.png diff --git a/tests/bugs/modalg_6/bug26310_4 b/tests/bugs/modalg_6/bug26310_4 new file mode 100644 index 0000000000..57c6dfa91f --- /dev/null +++ b/tests/bugs/modalg_6/bug26310_4 @@ -0,0 +1,50 @@ +puts "TODO OCC25929 ALL: ERROR in bopargcheck res1" +puts "TODO OCC25929 ALL: ERROR. res1 with continuity C0" +puts "TODO OCC25929 ALL: ERROR in bopargcheck res2" +puts "TODO OCC25929 ALL: ERROR. res2 with continuity C0" + +puts "========" +puts "OCC26310" +puts "========" +puts "" +################################################# +# Very slow boolean cut operations on cylinders +################################################# + +restore [locate_data_file OCC26310-b1.brep] b1 +restore [locate_data_file OCC26310-b2.brep] b2 + +bop b2 b1 + +bopcut res1 +boptuc res2 + +checkshape res1 +checkshape res2 + +set log1 [bopargcheck res1 #F] +set log2 [bopargcheck res2 #F] + +if { [string first "Faulties for FIRST shape found : 2" $log1] >= 0 } { + puts "ERROR in bopargcheck res1" +} + +if { [string first "Shapes with Continuity C0 : YES Cases(2) Total shapes(2)" $log1] >= 0 } { + puts "ERROR. res1 with continuity C0." +} + +if { [string first "Faulties for FIRST shape found : 2" $log2] >= 0 } { + puts "ERROR in bopargcheck res2" +} + +if { [string first "Shapes with Continuity C0 : YES Cases(2) Total shapes(2)" $log2] >= 0 } { + puts "ERROR. res2 with continuity C0." +} + +smallview +donly res1 +fit +xwd ${imagedir}/${casename}_1.png +donly res2 +fit +xwd ${imagedir}/${casename}_2.png