diff --git a/src/Mod/Part/App/FT2FC.cpp b/src/Mod/Part/App/FT2FC.cpp index c8e9a4bd11f3..41826b12d618 100644 --- a/src/Mod/Part/App/FT2FC.cpp +++ b/src/Mod/Part/App/FT2FC.cpp @@ -48,6 +48,7 @@ # include # include # include +# include # include # include # include @@ -55,6 +56,8 @@ # include # include # include +#include +#include #endif // _PreComp #include @@ -71,6 +74,8 @@ #include "FT2FC.h" +#define CLOCKWISE 0 +#define ANTICLOCKWISE 1 using namespace Part; typedef unsigned long UNICHAR; // ul is FT2's codepoint type <=> Py_UNICODE2/4 @@ -79,6 +84,7 @@ typedef unsigned long UNICHAR; // ul is FT2's codepoint type <=> Py_UN PyObject* getGlyphContours(FT_Face FTFont, UNICHAR currchar, double PenPos, double Scale,int charNum, double tracking); FT_Vector getKerning(FT_Face FTFont, UNICHAR lc, UNICHAR rc); TopoDS_Wire edgesToWire(std::vector Edges); +int calcClockDir(std::vector points); // for compatibility with old version - separate path & filename PyObject* FT2FC(const Py_UNICODE *PyUString, @@ -120,7 +126,6 @@ PyObject* FT2FC(const Py_UNICODE *PyUString, throw std::runtime_error(ErrorMsg.str()); } - #ifdef FC_OS_WIN32 Base::FileInfo fi(FontSpec); if (!fi.isReadable()) { @@ -195,7 +200,9 @@ PyObject* FT2FC(const Py_UNICODE *PyUString, // FT Decomp Context for 1 char struct FTDC_Ctx { std::vector Wires; + std::vector wDir; std::vector Edges; + std::vector polyPoints; UNICHAR currchar; FT_Vector LastVert; Handle(Geom_Surface) surf; @@ -209,8 +216,14 @@ static int move_cb(const FT_Vector* pt, void* p) { TopoDS_Wire newwire = edgesToWire(dc->Edges); dc->Wires.push_back(newwire); dc->Edges.clear(); + dc->wDir.push_back(calcClockDir(dc->polyPoints)); + dc->polyPoints.clear(); } dc->LastVert = *pt; + if (dc->polyPoints.empty()) { + dc->polyPoints.push_back(Base::Vector3d(pt->x, pt->y, 0.0)); + } + return 0; } @@ -224,6 +237,7 @@ static int line_cb(const FT_Vector* pt, void* p) { TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(lseg , dc->surf); dc->Edges.push_back(edge); dc->LastVert = *pt; + dc->polyPoints.push_back(Base::Vector3d(pt->x, pt->y, 0.0)); } return 0; } @@ -240,9 +254,18 @@ static int quad_cb(const FT_Vector* pt0, const FT_Vector* pt1, void* p) { Poles.SetValue(2, c1); Poles.SetValue(3, v2); Handle(Geom2d_BezierCurve) bcseg = new Geom2d_BezierCurve(Poles); - TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(bcseg , dc->surf); + double u,v; + u = bcseg->FirstParameter(); + v = bcseg->LastParameter(); + ShapeConstruct_Curve scc; + Handle(Geom2d_BSplineCurve) spline = scc.ConvertToBSpline(bcseg, u, v, Precision::Confusion()); + if (spline.IsNull()) { + Base::Console().Message("Conversion to B-spline failed"); + } + TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(spline , dc->surf); dc->Edges.push_back(edge); dc->LastVert = *pt1; + dc->polyPoints.push_back(Base::Vector3d(pt1->x, pt1->y, 0.0)); return 0; } @@ -260,9 +283,18 @@ static int cubic_cb(const FT_Vector* pt0, const FT_Vector* pt1, const FT_Vector* Poles.SetValue(3, c2); Poles.SetValue(4, v2); Handle(Geom2d_BezierCurve) bcseg = new Geom2d_BezierCurve(Poles); - TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(bcseg , dc->surf); + double u,v; + u = bcseg->FirstParameter(); + v = bcseg->LastParameter(); + ShapeConstruct_Curve scc; + Handle(Geom2d_BSplineCurve) spline = scc.ConvertToBSpline(bcseg, u, v, Precision::Confusion()); + if (spline.IsNull()) { + Base::Console().Message("Conversion to B-spline failed"); + } + TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(spline , dc->surf); dc->Edges.push_back(edge); dc->LastVert = *pt2; + dc->polyPoints.push_back(Base::Vector3d(pt2->x, pt2->y, 0.0)); return 0; } @@ -297,8 +329,19 @@ PyObject* getGlyphContours(FT_Face FTFont, UNICHAR currchar, double PenPos, doub // make the last TopoDS_Wire if (!ctx.Edges.empty()){ ctx.Wires.push_back(edgesToWire(ctx.Edges)); + ctx.wDir.push_back(calcClockDir(ctx.polyPoints)); } - /*FT_Orientation fontClass =*/ FT_Outline_Get_Orientation(&FTFont->glyph->outline); + +//a ttf outer contour is clockwise with material on the right. +//an occ outer contour has material on the left, so it must be reversed? + + + FT_Orientation ftOrient = FT_Outline_Get_Orientation(&FTFont->glyph->outline); + bool isTTF = false; + if (ftOrient == FT_ORIENTATION_TRUETYPE) { + isTTF = true; + } + PyObject* ret = PyList_New(0); gp_Vec pointer = gp_Vec(PenPos * Scale + charNum*tracking,0.0,0.0); @@ -308,7 +351,22 @@ PyObject* getGlyphContours(FT_Face FTFont, UNICHAR currchar, double PenPos, doub BRepBuilderAPI_Transform BRepScale(xForm); bool bCopy = true; // no effect? - for(std::vector::iterator iWire=ctx.Wires.begin();iWire != ctx.Wires.end();++iWire) { + + int wCount = 0; + for(std::vector::iterator iWire=ctx.Wires.begin();iWire != ctx.Wires.end(); ++iWire, wCount++) { + if ((ctx.wDir[wCount] == CLOCKWISE) && isTTF) { //ttf outer wire. fill inside / right + (*iWire).Orientation(TopAbs_REVERSED); + } else if ((ctx.wDir[wCount] == CLOCKWISE) && !isTTF) { //ps inner wire. fill outside / right + (*iWire).Orientation(TopAbs_REVERSED); + } else if ((ctx.wDir[wCount] == ANTICLOCKWISE) && isTTF) { //ttf inner wire. fill outside / left + (*iWire).Orientation(TopAbs_REVERSED); + } else if ((ctx.wDir[wCount] == ANTICLOCKWISE) && !isTTF) { //ps outer wire. fill inside / left + (*iWire).Orientation(TopAbs_REVERSED); + } else { + //this is likely a poorly constructed font (ex a ttf with outer wires ACW ) + Base::Console().Message("FT2FC::getGlyphContours - indeterminate wire direction\n"); + } + BRepScale.Perform(*iWire,bCopy); if (!BRepScale.IsDone()) { ErrorMsg << "FT2FC OCC BRepScale failed \n"; @@ -354,5 +412,25 @@ TopoDS_Wire edgesToWire(std::vector Edges) { return(occwire); } +//is polygon formed by points clockwise (0) or anticlockwise(1) +int calcClockDir(std::vector points) +{ + int result = CLOCKWISE; + int stop = points.size() - 1; + int iPoint = 0; + double bigArea = 0; + for ( ; iPoint < stop; iPoint++) { + double area = points[iPoint].x * points[iPoint + 1].y - + points[iPoint + 1].x * points[iPoint].y; + bigArea += area; + } + double area = points.back().x * points.front().y - + points.front().x * points.back().y; + bigArea += area; + if (bigArea < 0) { + result = ANTICLOCKWISE; + } + return result; +} #endif //#ifdef FCUseFreeType