1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-04 18:06:22 +03:00

Class BRepLib_ToleranceRule was created to work with shape tolerances by

tolerance rule.

Some code from BRepLib was moved to BRepLib_ToleranceRule.
This commit is contained in:
abk 2013-02-27 18:26:08 +04:00
parent 2f9c163f7e
commit 67f8838ff2
5 changed files with 455 additions and 151 deletions

View File

@ -86,6 +86,7 @@
#include <BRepBndLib.hxx>
#include <Approx_CurvilinearParameter.hxx>
#include <Geom_BSplineSurface.hxx>
#include <BRepLib_ToleranceRule.hxx>
// TODO - not thread-safe static variables
@ -1308,159 +1309,12 @@ void BRepLib::SameParameter(const TopoDS_Edge& AnEdge,
//=======================================================================
//function : UpdateTolerances
//purpose :
//purpose :
//=======================================================================
void BRepLib::UpdateTolerances(const TopoDS_Shape& aShape,
const Standard_Boolean verifyTolerance)
void BRepLib::UpdateTolerances(const TopoDS_Shape & theS,
const Standard_Boolean theMinimizeTolerances)
{
// Harmonize tolerances
// with rule Tolerance(VERTEX)>=Tolerance(EDGE)>=Tolerance(FACE)
BRep_Builder B;
Standard_Real tol=0;
if (verifyTolerance) {
// Set tolerance to its minimum value
Handle(Geom_Surface) S;
TopLoc_Location l;
TopExp_Explorer ex;
Bnd_Box aB;
Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax, dMax;
for (ex.Init(aShape, TopAbs_FACE); ex.More(); ex.Next()) {
const TopoDS_Face& curf=TopoDS::Face(ex.Current());
S = BRep_Tool::Surface(curf, l);
if (!S.IsNull()) {
aB.SetVoid();
BRepBndLib::Add(curf,aB);
if (S->DynamicType() == STANDARD_TYPE(Geom_RectangularTrimmedSurface)) {
S = (*((Handle(Geom_RectangularTrimmedSurface)*)&S))->BasisSurface();
}
GeomAdaptor_Surface AS(S);
switch (AS.GetType()) {
case GeomAbs_Plane:
case GeomAbs_Cylinder:
case GeomAbs_Cone:
{
tol=Precision::Confusion();
break;
}
case GeomAbs_Sphere:
case GeomAbs_Torus:
{
tol=Precision::Confusion()*2;
break;
}
default:
tol=Precision::Confusion()*4;
}
if (!aB.IsWhole()) {
aB.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
dMax=1.;
if (!aB.IsOpenXmin() && !aB.IsOpenXmax()) dMax=aXmax-aXmin;
if (!aB.IsOpenYmin() && !aB.IsOpenYmax()) aYmin=aYmax-aYmin;
if (!aB.IsOpenZmin() && !aB.IsOpenZmax()) aZmin=aZmax-aZmin;
if (aYmin>dMax) dMax=aYmin;
if (aZmin>dMax) dMax=aZmin;
tol=tol*dMax;
// Do not process tolerances > 1.
if (tol>1.) tol=0.99;
}
const Handle(BRep_TFace)& Tf = *((Handle(BRep_TFace)*)&curf.TShape());
Tf->Tolerance(tol);
}
}
}
//Process edges
TopTools_IndexedDataMapOfShapeListOfShape parents;
TopExp::MapShapesAndAncestors(aShape, TopAbs_EDGE, TopAbs_FACE, parents);
TopTools_ListIteratorOfListOfShape lConx;
Standard_Integer iCur;
for (iCur=1; iCur<=parents.Extent(); iCur++) {
tol=0;
for (lConx.Initialize(parents(iCur)); lConx.More(); lConx.Next()) {
tol=Max(tol, BRep_Tool::Tolerance(TopoDS::Face(lConx.Value())));
}
// Update can only increase tolerance, so if the edge has a greater
// tolerance than its faces it is not concerned
B.UpdateEdge(TopoDS::Edge(parents.FindKey(iCur)), tol);
}
//Vertices are processed
parents.Clear();
TopExp::MapShapesAndAncestors(aShape, TopAbs_VERTEX, TopAbs_EDGE, parents);
TColStd_MapOfTransient Initialized;
TopTools_MapOfShape Done;
Standard_Integer nbV = parents.Extent();
for (iCur=1; iCur<=nbV; iCur++) {
tol=0;
Done.Clear();
const TopoDS_Vertex& V = TopoDS::Vertex(parents.FindKey(iCur));
Bnd_Box box;
box.Add(BRep_Tool::Pnt(V));
gp_Pnt p3d;
for (lConx.Initialize(parents(iCur)); lConx.More(); lConx.Next()) {
const TopoDS_Edge& E = TopoDS::Edge(lConx.Value());
if(!Done.Add(E)) continue;
tol=Max(tol, BRep_Tool::Tolerance(E));
if(!BRep_Tool::SameRange(E)) continue;
Standard_Real par = BRep_Tool::Parameter(V,E);
Handle(BRep_TEdge)& TE = *((Handle(BRep_TEdge)*)&E.TShape());
BRep_ListIteratorOfListOfCurveRepresentation itcr(TE->Curves());
const TopLoc_Location& Eloc = E.Location();
while (itcr.More()) {
// For each CurveRepresentation, check the provided parameter
const Handle(BRep_CurveRepresentation)& cr = itcr.Value();
const TopLoc_Location& loc = cr->Location();
TopLoc_Location L = (Eloc * loc);
if (cr->IsCurve3D()) {
const Handle(Geom_Curve)& C = cr->Curve3D();
if (!C.IsNull()) { // edge non degenerated
p3d = C->Value(par);
p3d.Transform(L.Transformation());
box.Add(p3d);
}
}
else if (cr->IsCurveOnSurface()) {
const Handle(Geom_Surface)& Su = cr->Surface();
const Handle(Geom2d_Curve)& PC = cr->PCurve();
Handle(Geom2d_Curve) PC2;
if (cr->IsCurveOnClosedSurface()) {
PC2 = cr->PCurve2();
}
gp_Pnt2d p2d = PC->Value(par);
p3d = Su->Value(p2d.X(),p2d.Y());
p3d.Transform(L.Transformation());
box.Add(p3d);
if (!PC2.IsNull()) {
p2d = PC2->Value(par);
p3d = Su->Value(p2d.X(),p2d.Y());
p3d.Transform(L.Transformation());
box.Add(p3d);
}
}
itcr.Next();
}
}
Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
box.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
aXmax -= aXmin; aYmax -= aYmin; aZmax -= aZmin;
tol = Max(tol,sqrt(aXmax*aXmax+aYmax*aYmax+aZmax*aZmax));
tol += 2.*Epsilon(tol);
if (verifyTolerance) {
// ASet minimum value of the tolerance
// Attention to sharing of the vertex by other shapes
const Handle(BRep_TVertex)& TV = *((Handle(BRep_TVertex)*)&V.TShape());
if (Initialized.Add(TV))
TV->Tolerance(tol);
else
B.UpdateVertex(V, tol);
}
else {
// Update can only increase tolerance, so if the edge has a greater
// tolerance than its faces it is not concerned
B.UpdateVertex(V, tol);
}
}
BRepLib_ToleranceRule::SetProperTolerances(theS, theMinimizeTolerances);
}
//=======================================================================

View File

@ -0,0 +1,255 @@
// Copyright (c) 1999-2012 OPEN CASCADE SAS
//
// The content of this file is subject to the Open CASCADE Technology Public
// License Version 6.5 (the "License"). You may not use the content of this file
// except in compliance with the License. Please obtain a copy of the License
// at http://www.opencascade.org and read it completely before using this file.
//
// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
//
// The Original Code and all software distributed under the License is
// distributed on an "AS IS" basis, without warranty of any kind, and the
// Initial Developer hereby disclaims all such warranties, including without
// limitation, any warranties of merchantability, fitness for a particular
// purpose or non-infringement. Please see the License for the specific terms
// and conditions governing the rights and limitations under the License.
#include <BRepLib_ToleranceRule.hxx>
#include <Bnd_Box.hxx>
#include <BRep_CurveRepresentation.hxx>
#include <BRep_ListIteratorOfListOfCurveRepresentation.hxx>
#include <BRepBndLib.hxx>
#include <Geom_Curve.hxx>
#include <Geom_Surface.hxx>
#include <Geom_RectangularTrimmedSurface.hxx>
#include <Geom2d_Curve.hxx>
#include <GeomAdaptor_Surface.hxx>
#include <gp_Pnt.hxx>
#include <BRep_Tool.hxx>
#include <Precision.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Vertex.hxx>
//=======================================================================
//function : ProperTolerances
//purpose :
//=======================================================================
void BRepLib_ToleranceRule::ProperTolerances(const TopoDS_Shape & theS,
NCollection_DataMap<TopoDS_Shape, Standard_Real,
TopTools_ShapeMapHasher> & theTs,
Standard_Boolean theMinimizeTolerances)
{
// Process faces.
for (TopExp_Explorer aFIt(theS, TopAbs_FACE); aFIt.More(); aFIt.Next())
{
const TopoDS_Face & aF = TopoDS::Face(aFIt.Current());
Standard_Real aFT = Precision::Confusion() * 4;
if (!theMinimizeTolerances)
{
aFT = BRep_Tool::Tolerance(aF);
}
else
{
TopLoc_Location aL;
Handle_Geom_Surface aS = BRep_Tool::Surface(aF, aL);
if (!aS.IsNull())
{
if (theTs.IsBound(aF))
{
continue;
}
if (aS->DynamicType() == STANDARD_TYPE(Geom_RectangularTrimmedSurface))
{
Handle_Geom_RectangularTrimmedSurface aTS =
Handle_Geom_RectangularTrimmedSurface::DownCast(aS);
aS = aTS->BasisSurface();
}
//
switch (GeomAdaptor_Surface(aS).GetType())
{
case GeomAbs_Plane:
case GeomAbs_Cylinder:
case GeomAbs_Cone:
{
aFT = Precision::Confusion();
break;
}
case GeomAbs_Sphere:
case GeomAbs_Torus:
{
aFT = Precision::Confusion() * 2;
}
}
//
Bnd_Box aBox;
BRepBndLib::Add(aF, aBox);
if (!aBox.IsWhole())
{
Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
aBox.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
Standard_Real dMax = 1;
if (!aBox.IsOpenXmin() && !aBox.IsOpenXmax())
{
dMax = aXmax - aXmin;
}
if (!aBox.IsOpenYmin() && !aBox.IsOpenYmax())
{
aYmin = aYmax - aYmin;
}
if (!aBox.IsOpenZmin() && !aBox.IsOpenZmax())
{
aZmin = aZmax - aZmin;
}
if (dMax < aYmin)
{
dMax = aYmin;
}
if (dMax < aZmin)
{
dMax = aZmin;
}
aFT = aFT * dMax;
// Do not process tolerances > 1.
if (1 < aFT) aFT = 0.99;
}
}
theTs.Bind(aF, aFT);
}
// Process face edges.
for (TopExp_Explorer anEIt(aF, TopAbs_EDGE); anEIt.More(); anEIt.Next())
{
const TopoDS_Edge & anE = TopoDS::Edge(anEIt.Current());
Standard_Real anET = Max(aFT, BRep_Tool::Tolerance(anE));
if (!theTs.IsBound(anE))
{
theTs.Bind(anE, anET);
}
else
{
Standard_Real & aT = theTs(anE);
anET = Max(anET, aT);
aT = anET;
}
// Process face edge vertices.
for (TopExp_Explorer aVIt(anE, TopAbs_VERTEX); aVIt.More(); aVIt.Next())
{
const TopoDS_Vertex & aV = TopoDS::Vertex(aVIt.Current());
Standard_Real aVT = anET;
if (!theMinimizeTolerances)
{
aVT = Max(anET, BRep_Tool::Tolerance(aV));
}
//
if (BRep_Tool::SameRange(anE))
{
Bnd_Box aBox;
aBox.Add(BRep_Tool::Pnt(aV));
Standard_Real aPar = BRep_Tool::Parameter(aV, anE);
Handle_BRep_TEdge & anED = (Handle_BRep_TEdge &)anE.TShape();
const TopLoc_Location & anEL = anE.Location();
for (BRep_ListIteratorOfListOfCurveRepresentation
aRIt(anED->Curves()); aRIt.More(); aRIt.Next())
{
// For each CurveRepresentation, check the provided parameter
const Handle_BRep_CurveRepresentation & aR = aRIt.Value();
const TopLoc_Location & aRL = aR->Location();
TopLoc_Location aL = anEL * aRL;
if (aR->IsCurve3D())
{
const Handle_Geom_Curve & aC = aR->Curve3D();
if (!aC.IsNull())
{
// edge non degenerated
gp_Pnt aPnt = aC->Value(aPar);
aPnt.Transform(aL.Transformation());
aBox.Add(aPnt);
}
}
else if (aR->IsCurveOnSurface())
{
const Handle_Geom_Surface & aS = aR->Surface();
const Handle_Geom2d_Curve & aC = aR->PCurve();
const Handle_Geom2d_Curve * aC2 = 0;
if (aR->IsCurveOnClosedSurface())
{
aC2 = &(aR->PCurve2());
}
gp_Pnt2d a2DP = aC->Value(aPar);
gp_Pnt a3DP = aS->Value(a2DP.X(), a2DP.Y());
a3DP.Transform(aL.Transformation());
aBox.Add(a3DP);
if (aC2 != 0)
{
a2DP = (*aC2)->Value(aPar);
a3DP = aS->Value(a2DP.X(), a2DP.Y());
a3DP.Transform(aL.Transformation());
aBox.Add(a3DP);
}
}
}
//
Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
aBox.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
aXmax -= aXmin; aYmax -= aYmin; aZmax -= aZmin;
Standard_Real aT =
sqrt(aXmax * aXmax + aYmax * aYmax + aZmax * aZmax);
aT += 2 * Epsilon(aT);
aVT = Max(aVT, aT);
}
//
if (!theTs.IsBound(aV))
{
theTs.Bind(aV, aVT);
}
else
{
Standard_Real & aT = theTs(aV);
aT = Max(aVT, aT);
}
}
}
// Process face vertices.
for (TopExp_Explorer aVIt(aF, TopAbs_VERTEX, TopAbs_EDGE);
aVIt.More(); aVIt.Next())
{
const TopoDS_Vertex & aV = TopoDS::Vertex(aVIt.Current());
Standard_Real aVT = Max(aFT, BRep_Tool::Tolerance(aV));
if (!theTs.IsBound(aV))
{
theTs.Bind(aV, aVT);
}
else
{
Standard_Real & aT = theTs(aV);
aT = Max(aVT, aT);
}
}
}
// Process edges without faces.
for (TopExp_Explorer anEIt(theS, TopAbs_EDGE, TopAbs_FACE);
anEIt.More(); anEIt.Next())
{
const TopoDS_Edge & anE = TopoDS::Edge(anEIt.Current());
Standard_Real anET = BRep_Tool::Tolerance(anE);
// Process edge vertices.
for (TopExp_Explorer aVIt(anE, TopAbs_VERTEX); aVIt.More(); aVIt.Next())
{
const TopoDS_Vertex & aV = TopoDS::Vertex(aVIt.Current());
Standard_Real aVT = Max(anET, BRep_Tool::Tolerance(aV));
if (!theTs.IsBound(aV))
{
theTs.Bind(aV, aVT);
}
else
{
Standard_Real & aT = theTs(aV);
aT = Max(aVT, aT);
}
}
}
}

View File

@ -0,0 +1,75 @@
// Copyright (c) 1999-2012 OPEN CASCADE SAS
//
// The content of this file is subject to the Open CASCADE Technology Public
// License Version 6.5 (the "License"). You may not use the content of this file
// except in compliance with the License. Please obtain a copy of the License
// at http://www.opencascade.org and read it completely before using this file.
//
// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
//
// The Original Code and all software distributed under the License is
// distributed on an "AS IS" basis, without warranty of any kind, and the
// Initial Developer hereby disclaims all such warranties, including without
// limitation, any warranties of merchantability, fitness for a particular
// purpose or non-infringement. Please see the License for the specific terms
// and conditions governing the rights and limitations under the License.
#ifndef _BRepLib_ToleranceRule_HeaderFile
#define _BRepLib_ToleranceRule_HeaderFile
#include <BRep_TEdge.hxx>
#include <BRep_TFace.hxx>
#include <BRep_TVertex.hxx>
#include <NCollection_DataMap.hxx>
#include <TopTools_ShapeMapHasher.hxx>
//! The type is intended to work with shape tolerances by tolerance rule.<br>
class BRepLib_ToleranceRule
{
public:
DEFINE_STANDARD_ALLOC
//! In shape theS context calculates proper tolerance theTs(S) for every
//! shape theS shape S so that
//! - S is edge contained by a face of shape theS or
//! - S is vertex contained by an edge or a face of shape theS.
//! Shape S tolerance t(S) may be only increased:
//! t(S) <= theTs(S).
//! Calculation is made by the tolerance rule:
//! face F contains edge E ==> t(F) <= theTs(E),
//! edge E contains vertex V ==> theTs(E) <= theTs(V),
//! face F contains vertex V ==> t(F) <= theTs(V).
//!
//! If flag theMinimizeTolerances is Standard_True then
//! - theTs(F) is calculated for every face F of shape theS as
//! only face F type and size dependent value,
//! - theTs(F) is used instead of t(F),
//! - tolerance of vertex V representations is used instead of t(V).
Standard_EXPORT static void ProperTolerances(const TopoDS_Shape & theS,
NCollection_DataMap<TopoDS_Shape, Standard_Real,
TopTools_ShapeMapHasher> & theTs,
Standard_Boolean theMinimizeTolerances = Standard_False);
//! Auxiliary method. Returns Standard_False.
Standard_Boolean IsProtectedFromModification(
const TopoDS_Shape & theS) const;
//! The method is intended for any class T which contains method
//! IsProtectedFromModification with the following definition:
//! Standard_Boolean IsProtectedFromModification(
//! const TopoDS_Shape & theShape) const.
//! Gets proper tolerances by
//! ProperTolerances(theS, aTs, theMinimizeTolerances).
//! Toleranse t(S) is set to aTs(S) for every shape S so that
//! aTs.IsBound(S) is Standard_True and
//! theObj.IsProtectedFromModification(S) is Standard_False.
template <typename T> static void SetProperTolerances(
const TopoDS_Shape & theS, const T & theObj,
Standard_Boolean theMinimizeTolerances = Standard_False);
//! Calls SetProperTolerances(
//! theS, BRepLib_ToleranceRule(), theMinimizeTolerances).
static void SetProperTolerances(const TopoDS_Shape & theS,
Standard_Boolean theMinimizeTolerances = Standard_False);
};
#include <BRepLib_ToleranceRule.lxx>
#endif

View File

@ -0,0 +1,117 @@
// Copyright (c) 1999-2012 OPEN CASCADE SAS
//
// The content of this file is subject to the Open CASCADE Technology Public
// License Version 6.5 (the "License"). You may not use the content of this file
// except in compliance with the License. Please obtain a copy of the License
// at http://www.opencascade.org and read it completely before using this file.
//
// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
//
// The Original Code and all software distributed under the License is
// distributed on an "AS IS" basis, without warranty of any kind, and the
// Initial Developer hereby disclaims all such warranties, including without
// limitation, any warranties of merchantability, fitness for a particular
// purpose or non-infringement. Please see the License for the specific terms
// and conditions governing the rights and limitations under the License.
#include <TopExp_Explorer.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Vertex.hxx>
//=======================================================================
//function : IsProtectedFromModification
//purpose :
//=======================================================================
inline Standard_Boolean BRepLib_ToleranceRule::IsProtectedFromModification(
const TopoDS_Shape &) const
{
return Standard_False;
}
//=======================================================================
//function : SetProperTolerances
//purpose :
//=======================================================================
template <typename T>
void BRepLib_ToleranceRule::SetProperTolerances(const TopoDS_Shape & theS,
const T & theObj, Standard_Boolean theMinimizeTolerances)
{
// Get proper tolerances.
NCollection_DataMap<TopoDS_Shape, Standard_Real,
TopTools_ShapeMapHasher> aTs;
ProperTolerances(theS, aTs, theMinimizeTolerances);
// Process faces.
if (theMinimizeTolerances)
{
for (TopExp_Explorer aFIt(theS, TopAbs_FACE); aFIt.More(); aFIt.Next())
{
const TopoDS_Face & aF = TopoDS::Face(aFIt.Current());
if (!theObj.IsProtectedFromModification(aF))
{
Handle_BRep_TFace & aFD = Handle_BRep_TFace::DownCast(aF.TShape());
aFD->Tolerance(aTs(aF));
}
}
}
// Process edges and vertices with face.
for (TopExp_Explorer aFIt(theS, TopAbs_FACE); aFIt.More(); aFIt.Next())
{
const TopoDS_Face & aF = TopoDS::Face(aFIt.Current());
// Process face edges.
for (TopExp_Explorer anEIt(aF, TopAbs_EDGE); anEIt.More(); anEIt.Next())
{
const TopoDS_Edge & anE = TopoDS::Edge(anEIt.Current());
if (!theObj.IsProtectedFromModification(anE))
{
Handle_BRep_TEdge & anED = Handle_BRep_TEdge::DownCast(anE.TShape());
anED->Tolerance(aTs(anE));
}
// Process face edge vertices.
for (TopExp_Explorer aVIt(anE, TopAbs_VERTEX); aVIt.More(); aVIt.Next())
{
const TopoDS_Vertex & aV = TopoDS::Vertex(aVIt.Current());
if (!theObj.IsProtectedFromModification(aV))
{
Handle_BRep_TVertex & aVD =
Handle_BRep_TVertex::DownCast(aV.TShape());
aVD->Tolerance(aTs(aV));
}
}
}
// Process face vertices.
for (TopExp_Explorer aVIt(aF, TopAbs_VERTEX, TopAbs_EDGE);
aVIt.More(); aVIt.Next())
{
const TopoDS_Vertex & aV = TopoDS::Vertex(aVIt.Current());
if (!theObj.IsProtectedFromModification(aV))
{
Handle_BRep_TVertex & aVD = Handle_BRep_TVertex::DownCast(aV.TShape());
aVD->Tolerance(aTs(aV));
}
}
}
// Process edge vertices without faces.
for (TopExp_Explorer anEIt(theS, TopAbs_EDGE, TopAbs_FACE);
anEIt.More(); anEIt.Next())
{
const TopoDS_Edge & anE = TopoDS::Edge(anEIt.Current());
for (TopExp_Explorer aVIt(anE, TopAbs_VERTEX); aVIt.More(); aVIt.Next())
{
const TopoDS_Vertex & aV = TopoDS::Vertex(aVIt.Current());
if (!theObj.IsProtectedFromModification(aV))
{
Handle_BRep_TVertex & aVD = Handle_BRep_TVertex::DownCast(aV.TShape());
aVD->Tolerance(aTs(aV));
}
}
}
}
inline void BRepLib_ToleranceRule::SetProperTolerances(
const TopoDS_Shape & theS, Standard_Boolean theMinimizeTolerances)
{
SetProperTolerances(theS, BRepLib_ToleranceRule(), theMinimizeTolerances);
}

View File

@ -1 +1,4 @@
BRepLib_MakeWire_1.cxx
BRepLib_ToleranceRule.hxx
BRepLib_ToleranceRule.lxx
BRepLib_ToleranceRule.cxx