From 3388cf17dc9ec97814180227f11e679c8b3d26ec Mon Sep 17 00:00:00 2001 From: skl Date: Thu, 12 Jul 2018 09:47:02 +0300 Subject: [PATCH] 0025852: Visualization - Font_BRepFont produces bad faces for circled symbols Font_BRepFont now uses a dedicated algorithm for text-to-BRep transformation instead of relying on ShapeFix. It orders wires based on wire classification, analyzes internal zones and creates a few faces (if needed). TKService dependency from TKShHealing has been dropped. --- src/Font/Font_BRepFont.cxx | 229 ++++++++++++++++++++++++++++--------- src/Font/Font_BRepFont.hxx | 9 +- src/TKService/EXTERNLIB | 1 - tests/bugs/vis/bug25852 | 2 - 4 files changed, 185 insertions(+), 56 deletions(-) diff --git a/src/Font/Font_BRepFont.cxx b/src/Font/Font_BRepFont.cxx index 8f8dc94a7b..bd702487ae 100755 --- a/src/Font/Font_BRepFont.cxx +++ b/src/Font/Font_BRepFont.cxx @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -34,9 +35,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -45,6 +43,8 @@ #include #include #include +#include +#include #include #include FT_FREETYPE_H @@ -72,6 +72,46 @@ namespace return gp_XY (theScaleUnits * Standard_Real(theVec.x) * theWidthScaling / 64.0, theScaleUnits * Standard_Real(theVec.y) / 64.0); } + //! Auxiliary method for classification wire theW2 with respect to wire theW1 + static TopAbs_State classifyWW (const TopoDS_Wire& theW1, + const TopoDS_Wire& theW2, + const TopoDS_Face& theF) + { + TopAbs_State aRes = TopAbs_UNKNOWN; + + TopoDS_Face aF = TopoDS::Face (theF.EmptyCopied()); + aF.Orientation (TopAbs_FORWARD); + BRep_Builder aB; + aB.Add (aF, theW1); + BRepTopAdaptor_FClass2d aClass2d (aF, ::Precision::PConfusion()); + for (TopoDS_Iterator anEdgeIter (theW2); anEdgeIter.More(); anEdgeIter.Next()) + { + const TopoDS_Edge& anEdge = TopoDS::Edge (anEdgeIter.Value()); + Standard_Real aPFirst = 0.0, aPLast = 0.0; + Handle(Geom2d_Curve) aCurve2d = BRep_Tool::CurveOnSurface (anEdge, theF, aPFirst, aPLast); + if (aCurve2d.IsNull()) + { + continue; + } + + gp_Pnt2d aPnt2d = aCurve2d->Value ((aPFirst + aPLast) / 2.0); + TopAbs_State aState = aClass2d.Perform (aPnt2d, Standard_False); + if (aState == TopAbs_OUT + || aState == TopAbs_IN) + { + if (aRes == TopAbs_UNKNOWN) + { + aRes = aState; + } + else if (aRes != aState) + { + return TopAbs_UNKNOWN; + } + } + } + return aRes; + } + } // ======================================================================= @@ -98,15 +138,6 @@ void Font_BRepFont::init() myCurve2dAdaptor = new Geom2dAdaptor_HCurve(); Handle(Adaptor3d_HSurface) aSurfAdaptor = new GeomAdaptor_HSurface (mySurface); myCurvOnSurf.Load (aSurfAdaptor); - - myFixer.FixWireMode() = 1; - myFixer.FixOrientationMode() = 1; - myFixer.FixSplitFaceMode() = 1; // some glyphs might be composed from several faces - Handle(ShapeFix_Wire) aWireFixer = myFixer.FixWireTool(); - aWireFixer->FixConnectedMode() = 1; - aWireFixer->ClosedWireMode() = Standard_True; - Handle(ShapeBuild_ReShape) aContext = new ShapeBuild_ReShape(); - myFixer.SetContext (aContext); } // ======================================================================= @@ -241,6 +272,128 @@ bool Font_BRepFont::to3d (const Handle(Geom2d_Curve)& theCurve2d, return !theCurve3d.IsNull(); } + +// ======================================================================= +// function : buildFaces +// purpose : +// ======================================================================= +Standard_Boolean Font_BRepFont::buildFaces (const NCollection_Sequence& theWires, + TopoDS_Shape& theRes) +{ + // classify wires + NCollection_DataMap, TopTools_ShapeMapHasher> aMapOutInts; + TopTools_DataMapOfShapeInteger aMapNbOuts; + TopoDS_Face aF; + myBuilder.MakeFace (aF, mySurface, myPrecision); + Standard_Integer aWireIter1Index = 1; + for (NCollection_Sequence::Iterator aWireIter1 (theWires); aWireIter1.More(); ++aWireIter1Index, aWireIter1.Next()) + { + const TopoDS_Wire& aW1 = aWireIter1.Value(); + if (!aMapNbOuts.IsBound (aW1)) + { + const Standard_Integer aNbOuts = 0; + aMapNbOuts.Bind (aW1, aNbOuts); + } + + NCollection_Sequence* anIntWs = aMapOutInts.Bound (aW1, NCollection_Sequence()); + Standard_Integer aWireIter2Index = 1; + for (NCollection_Sequence::Iterator aWireIter2 (theWires); aWireIter2.More(); ++aWireIter2Index, aWireIter2.Next()) + { + if (aWireIter1Index == aWireIter2Index) + { + continue; + } + + const TopoDS_Wire& aW2 = aWireIter2.Value(); + const TopAbs_State aClass = classifyWW (aW1, aW2, aF); + if (aClass == TopAbs_IN) + { + anIntWs->Append (aW2); + if (Standard_Integer* aNbOutsPtr = aMapNbOuts.ChangeSeek (aW2)) + { + ++(*aNbOutsPtr); + } + else + { + const Standard_Integer aNbOuts = 1; + aMapNbOuts.Bind (aW2, aNbOuts); + } + } + } + } + + // check out wires and remove "not out" wires from maps + for (TopTools_DataMapIteratorOfDataMapOfShapeInteger anOutIter (aMapNbOuts); anOutIter.More(); anOutIter.Next()) + { + const Standard_Integer aTmp = anOutIter.Value() % 2; + if (aTmp > 0) + { + // not out wire + aMapOutInts.UnBind (anOutIter.Key()); + } + } + + // create faces for out wires + TopTools_MapOfShape anUsedShapes; + TopoDS_Compound aFaceComp; + myBuilder.MakeCompound (aFaceComp); + for (; !aMapOutInts.IsEmpty(); ) + { + // find out wire with max number of outs + TopoDS_Shape aW; + Standard_Integer aMaxNbOuts = -1; + for (NCollection_DataMap, TopTools_ShapeMapHasher>::Iterator itMOI (aMapOutInts); + itMOI.More(); itMOI.Next()) + { + const TopoDS_Shape& aKey = itMOI.Key(); + const Standard_Integer aNbOuts = aMapNbOuts.Find (aKey); + if (aNbOuts > aMaxNbOuts) + { + aMaxNbOuts = aNbOuts; + aW = aKey; + } + } + + // create face for selected wire + TopoDS_Face aNewF; + myBuilder.MakeFace (aNewF, mySurface, myPrecision); + myBuilder.Add (aNewF, aW); + anUsedShapes.Add (aW); + const NCollection_Sequence& anIns = aMapOutInts.Find (aW); + for (NCollection_Sequence::Iterator aWireIter (anIns); aWireIter.More(); aWireIter.Next()) + { + TopoDS_Wire aWin = aWireIter.Value(); + if (anUsedShapes.Contains (aWin)) + { + continue; + } + + aWin.Reverse(); + myBuilder.Add (aNewF, aWin); + anUsedShapes.Add (aWin); + } + + myBuilder.Add (aFaceComp, aNewF); + aMapOutInts.UnBind (aW); + } + + if (aFaceComp.NbChildren() == 0) + { + return Standard_False; + } + + if (aFaceComp.NbChildren() == 1) + { + theRes = TopoDS_Iterator (aFaceComp).Value(); + } + else + { + theRes = aFaceComp; + } + return Standard_True; +} + + // ======================================================================= // function : renderGlyph // purpose : @@ -265,7 +418,7 @@ Standard_Boolean Font_BRepFont::renderGlyph (const Standard_Utf32Char theChar, return Standard_False; TopLoc_Location aLoc; - TopoDS_Face aFaceDraft; + NCollection_Sequence aWires; TopoDS_Compound aFaceCompDraft; // Get orientation is useless since it doesn't retrieve any in-font information and just computes orientation. @@ -456,16 +609,18 @@ Standard_Boolean Font_BRepFont::renderGlyph (const Standard_Utf32Char theChar, TopoDS_Wire aWireDraft = aWireMaker.Wire(); if (!myIsSingleLine) { - //if (anOrient == FT_ORIENTATION_FILL_LEFT) - //{ - // According to the TrueType specification, clockwise contours must be filled - aWireDraft.Reverse(); - //} - if (aFaceDraft.IsNull()) + // collect all wires and set CCW orientation + TopoDS_Face aFace; + myBuilder.MakeFace (aFace, mySurface, myPrecision); + myBuilder.Add (aFace, aWireDraft); + BRepTopAdaptor_FClass2d aClass2d (aFace, ::Precision::PConfusion()); + TopAbs_State aState = aClass2d.PerformInfinitePoint(); + if (aState != TopAbs_OUT) { - myBuilder.MakeFace (aFaceDraft, mySurface, myPrecision); + // need to reverse + aWireDraft.Reverse(); } - myBuilder.Add (aFaceDraft, aWireDraft); + aWires.Append (aWireDraft); } else { @@ -477,37 +632,9 @@ Standard_Boolean Font_BRepFont::renderGlyph (const Standard_Utf32Char theChar, } } - if (!aFaceDraft.IsNull()) + if (!aWires.IsEmpty()) { - myFixer.Init (aFaceDraft); - myFixer.Perform(); - TopoDS_Shape aFixResult = myFixer.Result(); - if (!aFixResult.IsNull() - && aFixResult.ShapeType() != TopAbs_FACE) - { - // shape fix can not fix orientation within the single call - if (aFaceCompDraft.IsNull()) - { - myBuilder.MakeCompound (aFaceCompDraft); - } - for (TopExp_Explorer aFaceIter (aFixResult, TopAbs_FACE); aFaceIter.More(); aFaceIter.Next()) - { - TopoDS_Face aFace = TopoDS::Face (aFaceIter.Current()); - myFixer.Init (aFace); - myFixer.Perform(); - myBuilder.Add (aFaceCompDraft, myFixer.Result()); - } - theShape = aFaceCompDraft; - } - else if (!aFaceCompDraft.IsNull()) - { - myBuilder.Add (aFaceCompDraft, aFixResult); - theShape = aFaceCompDraft; - } - else - { - theShape = aFixResult; - } + buildFaces (aWires, theShape); } else if (!aFaceCompDraft.IsNull()) { diff --git a/src/Font/Font_BRepFont.hxx b/src/Font/Font_BRepFont.hxx index 51dec3d0d6..0dfa016f32 100755 --- a/src/Font/Font_BRepFont.hxx +++ b/src/Font/Font_BRepFont.hxx @@ -27,10 +27,11 @@ #include #include #include -#include #include #include #include +#include + //! This tool provides basic services for rendering of vectorized text glyphs as BRep shapes. //! Single instance initialize single font for sequential glyphs rendering with implicit caching of already rendered glyphs. @@ -190,6 +191,11 @@ private: const GeomAbs_Shape theContinuity, Handle(Geom_Curve)& theCurve3d); + //! Auxiliary method for creation faces from sequence of wires. + //! Splits to few faces (if it is needed) and updates orientation of wires. + Standard_Boolean buildFaces (const NCollection_Sequence& theWires, + TopoDS_Shape& theRes); + protected: //! @name Protected fields NCollection_DataMap @@ -208,7 +214,6 @@ protected: //! @name Shared temporary variables for glyph construction TColgp_Array1OfPnt2d my3Poles; TColgp_Array1OfPnt2d my4Poles; BRep_Builder myBuilder; - ShapeFix_Face myFixer; public: diff --git a/src/TKService/EXTERNLIB b/src/TKService/EXTERNLIB index a2bba11a83..32aba57c23 100755 --- a/src/TKService/EXTERNLIB +++ b/src/TKService/EXTERNLIB @@ -1,7 +1,6 @@ TKernel TKMath TKBRep -TKShHealing TKGeomBase TKGeomAlgo TKG2d diff --git a/tests/bugs/vis/bug25852 b/tests/bugs/vis/bug25852 index c5572ace07..31ae32c70f 100644 --- a/tests/bugs/vis/bug25852 +++ b/tests/bugs/vis/bug25852 @@ -1,5 +1,3 @@ -puts "TODO CR25852 ALL: Faulty shapes in variables faulty_1 to" - puts "============" puts "CR25852" puts "============"