Add a checking into files Geom_OffsetSurface.cxx, Geom_OffsetCurve.cxx, Geom2d_OffsetCurve.cxx , which try to make continuity of bspline surfaces and curves more than C0 to build offset.
Delete duplicate code and checkings
Prevent change of offset curve / surface when exception is raised due to attempt to set new C0 basis curve / surface
Added new QA command OCC23683. Added test case bugs/moddata_3/bug23683
-- . Curves and Surfaces for Computer Aided Geometric Design,
-- a practical guide Gerald Farin
-uses TColStd, gp, TColgp, math
+uses TColStd, gp, TColgp, math, GeomAbs
is
-- Analyses the distribution of multiplicities between
-- the knot FromK1 and the Knot ToK2.
+ KnotAnalysis (Degree : Integer;
+ Periodic : Boolean;
+ CKnots : Array1OfReal from TColStd;
+ CMults : Array1OfInteger from TColStd;
+ KnotForm : out BSplKnotDistribution from GeomAbs;
+ MaxKnotMult: out Integer);
+ ---Purpose: Analyzes the array of knots.
+ -- Returns the form and the maximum knot multiplicity.
+
Reparametrize (U1, U2 : Real;
Knots : in out Array1OfReal from TColStd);
---Purpose:
return MForm;
}
+//=======================================================================
+//function : KnotAnalysis
+//purpose :
+//=======================================================================
+
+void BSplCLib::KnotAnalysis (const Standard_Integer Degree,
+ const Standard_Boolean Periodic,
+ const TColStd_Array1OfReal& CKnots,
+ const TColStd_Array1OfInteger& CMults,
+ GeomAbs_BSplKnotDistribution& KnotForm,
+ Standard_Integer& MaxKnotMult)
+{
+ KnotForm = GeomAbs_NonUniform;
+
+ BSplCLib_KnotDistribution KSet =
+ BSplCLib::KnotForm (CKnots, 1, CKnots.Length());
+
+
+ if (KSet == BSplCLib_Uniform) {
+ BSplCLib_MultDistribution MSet =
+ BSplCLib::MultForm (CMults, 1, CMults.Length());
+ switch (MSet) {
+ case BSplCLib_NonConstant :
+ break;
+ case BSplCLib_Constant :
+ if (CKnots.Length() == 2) {
+ KnotForm = GeomAbs_PiecewiseBezier;
+ }
+ else {
+ if (CMults (1) == 1) KnotForm = GeomAbs_Uniform;
+ }
+ break;
+ case BSplCLib_QuasiConstant :
+ if (CMults (1) == Degree + 1) {
+ Standard_Real M = CMults (2);
+ if (M == Degree ) KnotForm = GeomAbs_PiecewiseBezier;
+ else if (M == 1) KnotForm = GeomAbs_QuasiUniform;
+ }
+ break;
+ }
+ }
+
+ Standard_Integer FirstKM =
+ Periodic ? CKnots.Lower() : BSplCLib::FirstUKnotIndex (Degree,CMults);
+ Standard_Integer LastKM =
+ Periodic ? CKnots.Upper() : BSplCLib::LastUKnotIndex (Degree,CMults);
+ MaxKnotMult = 0;
+ if (LastKM - FirstKM != 1) {
+ Standard_Integer Multi;
+ for (Standard_Integer i = FirstKM + 1; i < LastKM; i++) {
+ Multi = CMults (i);
+ MaxKnotMult = Max (MaxKnotMult, Multi);
+ }
+ }
+}
+
//=======================================================================
//function : Reparametrize
//purpose :
Standard_ConstructionError::Raise();
}
-//=======================================================================
-//function : KnotAnalysis
-//purpose : Internal use only
-//=======================================================================
-
-static void KnotAnalysis
-(const Standard_Integer Degree,
- const Standard_Boolean Periodic,
- const TColStd_Array1OfReal& CKnots,
- const TColStd_Array1OfInteger& CMults,
- GeomAbs_BSplKnotDistribution& KnotForm,
- Standard_Integer& MaxKnotMult)
-{
- KnotForm = GeomAbs_NonUniform;
-
- BSplCLib_KnotDistribution KSet =
- BSplCLib::KnotForm (CKnots, 1, CKnots.Length());
-
-
- if (KSet == BSplCLib_Uniform) {
- BSplCLib_MultDistribution MSet =
- BSplCLib::MultForm (CMults, 1, CMults.Length());
- switch (MSet) {
- case BSplCLib_NonConstant :
- break;
- case BSplCLib_Constant :
- if (CKnots.Length() == 2) {
- KnotForm = GeomAbs_PiecewiseBezier;
- }
- else {
- if (CMults (1) == 1) KnotForm = GeomAbs_Uniform;
- }
- break;
- case BSplCLib_QuasiConstant :
- if (CMults (1) == Degree + 1) {
- Standard_Real M = CMults (2);
- if (M == Degree ) KnotForm = GeomAbs_PiecewiseBezier;
- else if (M == 1) KnotForm = GeomAbs_QuasiUniform;
- }
- break;
- }
- }
-
- Standard_Integer FirstKM =
- Periodic ? CKnots.Lower() : BSplCLib::FirstUKnotIndex (Degree,CMults);
- Standard_Integer LastKM =
- Periodic ? CKnots.Upper() : BSplCLib::LastUKnotIndex (Degree,CMults);
- MaxKnotMult = 0;
- if (LastKM - FirstKM != 1) {
- Standard_Integer Multi;
- for (Standard_Integer i = FirstKM + 1; i < LastKM; i++) {
- Multi = CMults (i);
- MaxKnotMult = Max (MaxKnotMult, Multi);
- }
- }
-}
-
//=======================================================================
//function : Rational
//purpose : check rationality of an array of weights
rational = !weights.IsNull();
Standard_Integer MaxKnotMult = 0;
- KnotAnalysis (deg,
+ BSplCLib::KnotAnalysis (deg,
periodic,
knots->Array1(),
mults->Array1(),
Standard_ConstructionError::Raise("Geom_BSplineSurface");
}
-//=======================================================================
-//function : KnotAnalysis
-//purpose : Internal use only.
-//=======================================================================
-
-static void KnotAnalysis
-(const Standard_Integer Degree,
- const TColStd_Array1OfReal& CKnots,
- const TColStd_Array1OfInteger& CMults,
- GeomAbs_BSplKnotDistribution& KnotForm,
- Standard_Integer& MaxKnotMult)
-{
- KnotForm = GeomAbs_NonUniform;
-
- BSplCLib_KnotDistribution KSet =
- BSplCLib::KnotForm (CKnots, 1, CKnots.Length());
-
-
- if (KSet == BSplCLib_Uniform) {
- BSplCLib_MultDistribution MSet =
- BSplCLib::MultForm (CMults, 1, CMults.Length());
- switch (MSet) {
- case BSplCLib_NonConstant :
- break;
- case BSplCLib_Constant :
- if (CKnots.Length() == 2) {
- KnotForm = GeomAbs_PiecewiseBezier;
- }
- else {
- if (CMults (1) == 1) KnotForm = GeomAbs_Uniform;
- }
- break;
- case BSplCLib_QuasiConstant :
- if (CMults (1) == Degree + 1) {
- Standard_Real M = CMults (2);
- if (M == Degree ) KnotForm = GeomAbs_PiecewiseBezier;
- else if (M == 1) KnotForm = GeomAbs_QuasiUniform;
- }
- break;
- }
- }
-
- Standard_Integer FirstKM = BSplCLib::FirstUKnotIndex (Degree, CMults);
- Standard_Integer LastKM = BSplCLib::LastUKnotIndex (Degree, CMults);
- MaxKnotMult = 0;
- if (LastKM - FirstKM != 1) {
- Standard_Integer Multi;
- for (Standard_Integer i = FirstKM + 1; i < LastKM; i++) {
- Multi = CMults (i);
- MaxKnotMult = Max (MaxKnotMult, Multi);
- }
- }
-}
-
//=======================================================================
//function : Rational
//purpose : Internal use only.
{
Standard_Integer MaxKnotMult = 0;
- KnotAnalysis (udeg,
+ BSplCLib::KnotAnalysis (udeg, uperiodic,
uknots->Array1(),
umults->Array1(),
uknotSet, MaxKnotMult);
void Geom_BSplineSurface::UpdateVKnots()
{
Standard_Integer MaxKnotMult = 0;
- KnotAnalysis (vdeg,
+ BSplCLib::KnotAnalysis (vdeg, vperiodic,
vknots->Array1(),
vmults->Array1(),
vknotSet, MaxKnotMult);
Geom_OffsetCurve::Geom_OffsetCurve (const Handle(Curve)& C,
const Standard_Real Offset,
const Dir& V )
- : direction(V), offsetValue(Offset) {
-
+ : direction(V), offsetValue(Offset)
+{
if (C->DynamicType() == STANDARD_TYPE(Geom_OffsetCurve)) {
Handle(OffsetCurve) OC = Handle(OffsetCurve)::DownCast(C);
- if ((OC->BasisCurve())->Continuity() == GeomAbs_C0)
- Standard_ConstructionError::Raise();
+ SetBasisCurve (OC->BasisCurve());
- basisCurve = Handle(Curve)::DownCast((OC->BasisCurve())->Copy());
Standard_Real PrevOff = OC->Offset();
gp_Vec V1(OC->Direction());
gp_Vec V2(direction);
offsetValue = -Vdir.Magnitude();
direction.SetXYZ((-Vdir).XYZ());
}
- } else {
- if (C->Continuity() == GeomAbs_C0) Standard_ConstructionError::Raise();
- basisCurve = Handle(Curve)::DownCast(C->Copy()); // DownCast: 10-03-93
+ }
+ else {
+ SetBasisCurve(C);
}
}
//purpose :
//=======================================================================
-void Geom_OffsetCurve::SetBasisCurve (const Handle(Curve)& C) {
+void Geom_OffsetCurve::SetBasisCurve (const Handle(Curve)& C)
+{
+ Handle(Curve) aBasisCurve = Handle(Curve)::DownCast(C->Copy());
+
+ // Basis curve must be at least C1
+ if (aBasisCurve->Continuity() == GeomAbs_C0)
+ {
+ // For B-splines it is sometimes possible to increase continuity by removing
+ // unnecessarily duplicated knots
+ if (aBasisCurve->IsKind(STANDARD_TYPE(Geom_BSplineCurve)))
+ {
+ Handle(Geom_BSplineCurve) aBCurve = Handle(Geom_BSplineCurve)::DownCast(aBasisCurve);
+ Standard_Integer degree = aBCurve->Degree();
+ Standard_Real Toler = Precision::Confusion();
+ Standard_Integer start = aBCurve->IsPeriodic() ? 1 : aBCurve->FirstUKnotIndex(),
+ finish = aBCurve->IsPeriodic() ? aBCurve->NbKnots() : aBCurve->LastUKnotIndex();
+ for (Standard_Integer i = start; i <= finish; i++)
+ {
+ Standard_Integer mult = aBCurve->Multiplicity(i);
+ if ( mult == degree )
+ aBCurve->RemoveKnot(i,degree - 1, Toler);
+ }
+ }
+
+ // Raise exception if still C0
+ if (aBasisCurve->Continuity() == GeomAbs_C0)
+ Standard_ConstructionError::Raise("Offset on C0 curve");
+ }
- if (C->Continuity() == GeomAbs_C0) Standard_ConstructionError::Raise();
- basisCurve = Handle(Curve)::DownCast(C->Copy()); // DownCast: 10-03-93
+ basisCurve = aBasisCurve;
}
const Standard_Real Offset )
: offsetValue (Offset)
{
-
Handle(Geom_OffsetSurface) Off_S;
Off_S = Handle(Geom_OffsetSurface)::DownCast(S);
if (!Off_S.IsNull()) {
- offsetValue += Off_S->Offset();
- basisSurf = Handle(Surface)::DownCast(Off_S->BasisSurface()->Copy());
- }
+ offsetValue += Off_S->Offset();
+ SetBasisSurface (Off_S->BasisSurface());
+ }
else {
- basisSurf = Handle(Surface)::DownCast(S->Copy());
- if (S->Continuity() == GeomAbs_C0)
- Standard_ConstructionError::Raise("Offset with no C1 Surface");
+ SetBasisSurface(S);
}
- equivSurf = Surface();
+
//
// Tolerance en dur pour l'instant ,mais on devrait la proposer dans le constructeur
// et la mettre en champ, on pourrait utiliser par exemple pour l'extraction d'iso
//purpose :
//=======================================================================
-void Geom_OffsetSurface::SetBasisSurface (const Handle(Surface)& S) {
+void Geom_OffsetSurface::SetBasisSurface (const Handle(Surface)& S)
+{
+ Handle(Surface) aBasisSurf = Handle(Surface)::DownCast(S->Copy());
+
+ // Basis surface must be at least C1
+ if (aBasisSurf->Continuity() == GeomAbs_C0)
+ {
+ // For B-splines it is sometimes possible to increase continuity by removing
+ // unnecessarily duplicated knots
+ if (aBasisSurf->IsKind(STANDARD_TYPE(Geom_BSplineSurface)))
+ {
+ Handle(Geom_BSplineSurface) aBSurf = Handle(Geom_BSplineSurface)::DownCast(aBasisSurf);
+ Standard_Integer uDegree = aBSurf->UDegree(), vDegree = aBSurf->VDegree();
+ Standard_Real Toler = Precision::Confusion();
+ Standard_Integer start = aBSurf->IsUPeriodic() ? 1 : aBSurf->FirstUKnotIndex(),
+ finish = aBSurf->IsUPeriodic() ? aBSurf->NbUKnots() : aBSurf->LastUKnotIndex();
+ for (Standard_Integer i = start; i <= finish; i++)
+ {
+ Standard_Integer mult = aBSurf->UMultiplicity(i);
+ if ( mult == uDegree )
+ aBSurf->RemoveUKnot(i,uDegree - 1, Toler);
+ }
+ start = aBSurf->IsVPeriodic() ? 1 : aBSurf->FirstVKnotIndex();
+ finish = aBSurf->IsVPeriodic() ? aBSurf->NbVKnots() : aBSurf->LastVKnotIndex();
+ for (Standard_Integer i = start; i <= finish; i++)
+ {
+ Standard_Integer mult = aBSurf->VMultiplicity(i);
+ if ( mult == vDegree )
+ aBSurf->RemoveVKnot(i,vDegree - 1, Toler);
+ }
+ }
+
+ // Raise exception if still C0
+ if (aBasisSurf->Continuity() == GeomAbs_C0)
+ Standard_ConstructionError::Raise("Offset with no C1 Surface");
+ }
- basisSurf = Handle(Surface)::DownCast(S->Copy());
+ basisSurf = aBasisSurf;
equivSurf = Surface();
- if (S->Continuity() == GeomAbs_C0) Standard_ConstructionError::Raise();
}
Standard_ConstructionError::Raise("BSpline curve : # Poles and degree mismatch");
}
-//=======================================================================
-//function : KnotAnalysis
-//purpose : Internal use only
-//=======================================================================
-
-static void KnotAnalysis
-(const Standard_Integer Degree,
- const Standard_Boolean Periodic,
- const TColStd_Array1OfReal& CKnots,
- const TColStd_Array1OfInteger& CMults,
- GeomAbs_BSplKnotDistribution& KnotForm,
- Standard_Integer& MaxKnotMult)
-{
- KnotForm = GeomAbs_NonUniform;
-
- BSplCLib_KnotDistribution KSet =
- BSplCLib::KnotForm (CKnots, 1, CKnots.Length());
-
-
- if (KSet == BSplCLib_Uniform) {
- BSplCLib_MultDistribution MSet =
- BSplCLib::MultForm (CMults, 1, CMults.Length());
- switch (MSet) {
- case BSplCLib_NonConstant :
- break;
- case BSplCLib_Constant :
- if (CKnots.Length() == 2) {
- KnotForm = GeomAbs_PiecewiseBezier;
- }
- else {
- if (CMults (1) == 1) KnotForm = GeomAbs_Uniform;
- }
- break;
- case BSplCLib_QuasiConstant :
- if (CMults (1) == Degree + 1) {
- Standard_Real M = CMults (2);
- if (M == Degree ) KnotForm = GeomAbs_PiecewiseBezier;
- else if (M == 1) KnotForm = GeomAbs_QuasiUniform;
- }
- break;
- }
- }
-
- Standard_Integer FirstKM =
- Periodic ? CKnots.Lower() : BSplCLib::FirstUKnotIndex (Degree,CMults);
- Standard_Integer LastKM =
- Periodic ? CKnots.Upper() : BSplCLib::LastUKnotIndex (Degree,CMults);
- MaxKnotMult = 0;
- if (LastKM - FirstKM != 1) {
- Standard_Integer Multi;
- for (Standard_Integer i = FirstKM + 1; i < LastKM; i++) {
- Multi = CMults (i);
- MaxKnotMult = Max (MaxKnotMult, Multi);
- }
- }
-}
-
//=======================================================================
//function : Rational
//purpose : check rationality of an array of weights
rational = !weights.IsNull();
Standard_Integer MaxKnotMult = 0;
- KnotAnalysis (deg,
+ BSplCLib::KnotAnalysis (deg,
periodic,
knots->Array1(),
mults->Array1(),
{
if (C->DynamicType() == STANDARD_TYPE(Geom2d_OffsetCurve)) {
Handle(OffsetCurve) OC = Handle(OffsetCurve)::DownCast(C);
- if ((OC->BasisCurve())->Continuity() == GeomAbs_C0)
- Standard_ConstructionError::Raise();
-
- basisCurve = Handle(Curve)::DownCast((OC->BasisCurve())->Copy());
+ SetBasisCurve (OC->BasisCurve());
offsetValue += OC->Offset();
- } else {
- if (C->Continuity() == GeomAbs_C0)
- Standard_ConstructionError::Raise();
-
- basisCurve = Handle(Curve)::DownCast(C->Copy());
+ }
+ else {
+ SetBasisCurve(C);
}
}
void Geom2d_OffsetCurve::SetBasisCurve (const Handle(Curve)& C)
{
- if (C->Continuity() == GeomAbs_C0) Standard_ConstructionError::Raise();
- basisCurve = Handle(Geom2d_Curve)::DownCast(C->Copy());
+ Handle(Geom2d_Curve) aBasisCurve = Handle(Geom2d_Curve)::DownCast(C->Copy());
+
+ // Basis curve must be at least C1
+ if (aBasisCurve->Continuity() == GeomAbs_C0)
+ {
+ // For B-splines it is sometimes possible to increase continuity by removing
+ // unnecessarily duplicated knots
+ if (aBasisCurve->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve)))
+ {
+ Handle(Geom2d_BSplineCurve) aBCurve = Handle(Geom2d_BSplineCurve)::DownCast(aBasisCurve);
+ Standard_Integer degree = aBCurve->Degree();
+ Standard_Real Toler = 1e-7;
+ Standard_Integer start = aBCurve->IsPeriodic() ? 1 : aBCurve->FirstUKnotIndex(),
+ finish = aBCurve->IsPeriodic() ? aBCurve->NbKnots() : aBCurve->LastUKnotIndex();
+ for (Standard_Integer i = start; i <= finish; i++)
+ {
+ Standard_Integer mult = aBCurve->Multiplicity(i);
+ if ( mult == degree )
+ aBCurve->RemoveKnot(i,degree - 1, Toler);
+ }
+ }
+
+ // Raise exception if still C0
+ if (aBasisCurve->Continuity() == GeomAbs_C0)
+ Standard_ConstructionError::Raise("Offset on C0 curve");
+ }
+
+ basisCurve = aBasisCurve;
}
//=======================================================================
return 0;
}
+static Standard_Integer OCC23683 (Draw_Interpretor& di, Standard_Integer argc,const char ** argv)
+{
+ if (argc < 2) {
+ di<<"Usage: " << argv[0] << " invalid number of arguments"<<"\n";
+ return 1;
+ }
+
+ Standard_Integer ucontinuity = 1;
+ Standard_Integer vcontinuity = 1;
+ Standard_Boolean iscnu = false;
+ Standard_Boolean iscnv = false;
+
+ Handle(Geom_Surface) aSurf = DrawTrSurf::GetSurface(argv[1]);
+
+ QCOMPARE (aSurf->IsCNu (ucontinuity), iscnu);
+ QCOMPARE (aSurf->IsCNv (vcontinuity), iscnv);
+
+ return 0;
+}
+
void QABugs::Commands_19(Draw_Interpretor& theCommands) {
const char *group = "QABugs";
theCommands.Add ("OCC22611", "OCC22611 string nb", __FILE__, OCC22611, group);
theCommands.Add ("OCC22595", "OCC22595", __FILE__, OCC22595, group);
theCommands.Add ("OCC23774", "OCC23774 shape1 shape2", __FILE__, OCC23774, group);
+ theCommands.Add ("OCC23683", "OCC23683 shape", __FILE__, OCC23683, group);
return;
}
--- /dev/null
+puts "================"
+puts "OCC23683"
+puts "================"
+puts ""
+
+pload QAcommands
+
+restore [locate_data_file bug23683_a_31_draw] result
+set info [OCC23683 result]
+
+if { [regexp "iscnu: OK" $info] != 1 } {
+ puts "Error : ucontinuity is incorrect"
+}
+
+if { [regexp "iscnv: OK" $info] != 1 } {
+ puts "Error : vcontinuity is incorrect"
+}
+
+set 2dviewer 0
+