From 8b2c763e4a7756b85df0a579db890995482bf3ea Mon Sep 17 00:00:00 2001 From: WandererFan Date: Sat, 16 Mar 2013 17:07:05 -0400 Subject: [PATCH 1/9] Basic ASCII text to wire version. Breaks on Unicode. std::exception handling. --- CMakeLists.txt | 4 + cMake/FindFreeType.cmake | 117 ++++++++++++ src/Mod/Part/App/AppPartPy.cpp | 64 +++++++ src/Mod/Part/App/CMakeLists.txt | 4 + src/Mod/Part/App/FT2FC.cpp | 323 ++++++++++++++++++++++++++++++++ src/Mod/Part/App/FT2FC.h | 12 ++ 6 files changed, 524 insertions(+) create mode 100644 cMake/FindFreeType.cmake create mode 100644 src/Mod/Part/App/FT2FC.cpp create mode 100644 src/Mod/Part/App/FT2FC.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6d87248519..330916d21d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -323,6 +323,10 @@ MARK_AS_ADVANCED(FORCE FREECAD_LIBPACK_CHECKFILE6X FREECAD_LIBPACK_CHECKFILE7X) endforeach(it) endmacro(fc_wrap_cpp) +#--------------------FreeType----------------------- + find_package(FreeType) +#--------------------------------------------------- + if(FREECAD_BUILD_GUI) # -------------------------------- OpenGL -------------------------------- diff --git a/cMake/FindFreeType.cmake b/cMake/FindFreeType.cmake new file mode 100644 index 0000000000..0e16dd44a9 --- /dev/null +++ b/cMake/FindFreeType.cmake @@ -0,0 +1,117 @@ +# - Locate FreeType library +# This module defines +# FREETYPE_LIBRARY, the library to link against +# FREETYPE_FOUND, if false, do not try to link to FREETYPE +# FREETYPE_INCLUDE_DIRS, where to find headers. +# This is the concatenation of the paths: +# FREETYPE_INCLUDE_DIR_ft2build +# FREETYPE_INCLUDE_DIR_freetype2 +# +# $FREETYPE_DIR is an environment variable that would +# correspond to the ./configure --prefix=$FREETYPE_DIR +# used in building FREETYPE. +# Created by Eric Wing. + +# Ugh, FreeType seems to use some #include trickery which +# makes this harder than it should be. It looks like they +# put ft2build.h in a common/easier-to-find location which +# then contains a #include to a more specific header in a +# more specific location (#include ). +# Then from there, they need to set a bunch of #define's +# so you can do something like: +# #include FT_FREETYPE_H +# Unfortunately, using CMake's mechanisms like INCLUDE_DIRECTORIES() +# wants explicit full paths and this trickery doesn't work too well. +# I'm going to attempt to cut out the middleman and hope +# everything still works. +FIND_PATH(FREETYPE_INCLUDE_DIR_ft2build ft2build.h + PATHS + $ENV{FREETYPE_DIR} + NO_DEFAULT_PATH + PATH_SUFFIXES include +) +FIND_PATH(FREETYPE_INCLUDE_DIR_ft2build ft2build.h + PATHS ${CMAKE_PREFIX_PATH} # Unofficial: We are proposing this. + NO_DEFAULT_PATH + PATH_SUFFIXES include +) +FIND_PATH(FREETYPE_INCLUDE_DIR_ft2build ft2build.h + PATHS + /usr/local + /usr + /usr/local/X11R6 + /usr/local/X11 + /usr/X11R6 + /usr/X11 + /sw + /opt/local + /opt/csw + /opt + /usr/freeware + PATH_SUFFIXES include +) + +FIND_PATH(FREETYPE_INCLUDE_DIR_freetype2 freetype/config/ftheader.h + $ENV{FREETYPE_DIR}/include/freetype2 + NO_DEFAULT_PATH +) +FIND_PATH(FREETYPE_INCLUDE_DIR_freetype2 freetype/config/ftheader.h + PATHS ${CMAKE_PREFIX_PATH} # Unofficial: We are proposing this. + NO_DEFAULT_PATH + PATH_SUFFIXES include/freetype2 +) +FIND_PATH(FREETYPE_INCLUDE_DIR_freetype2 freetype/config/ftheader.h + /usr/local/include/freetype2 + /usr/include/freetype2 + /usr/local/X11R6/include/freetype2 + /usr/local/X11/include/freetype2 + /usr/X11R6/include/freetype2 + /usr/X11/include/freetype2 + /sw/include/freetype2 + /opt/local/include/freetype2 + /opt/csw/include/freetype2 + /opt/include/freetype2 + /usr/freeware/include/freetype2 +) + +FIND_LIBRARY(FREETYPE_LIBRARY + NAMES freetype libfreetype freetype219 + PATHS + $ENV{FREETYPE_DIR} + NO_DEFAULT_PATH + PATH_SUFFIXES lib64 lib +) +FIND_LIBRARY(FREETYPE_LIBRARY + NAMES freetype libfreetype freetype219 + PATHS ${CMAKE_PREFIX_PATH} # Unofficial: We are proposing this. + NO_DEFAULT_PATH + PATH_SUFFIXES lib64 lib +) +FIND_LIBRARY(FREETYPE_LIBRARY + NAMES freetype libfreetype freetype219 + PATHS + /usr/local + /usr + /usr/local/X11R6 + /usr/local/X11 + /usr/X11R6 + /usr/X11 + /sw + /opt/local + /opt/csw + /opt + /usr/freeware + PATH_SUFFIXES lib64 lib +) + +IF(FREETYPE_INCLUDE_DIR_ft2build AND FREETYPE_INCLUDE_DIR_freetype2) + SET(FREETYPE_INCLUDE_DIRS "${FREETYPE_INCLUDE_DIR_ft2build};${FREETYPE_INCLUDE_DIR_freetype2}") +ENDIF(FREETYPE_INCLUDE_DIR_ft2build AND FREETYPE_INCLUDE_DIR_freetype2) + + +SET(FREETYPE_FOUND "NO") +IF(FREETYPE_LIBRARY AND FREETYPE_INCLUDE_DIRS) + SET(FREETYPE_FOUND "YES") +ENDIF(FREETYPE_LIBRARY AND FREETYPE_INCLUDE_DIRS) + + diff --git a/src/Mod/Part/App/AppPartPy.cpp b/src/Mod/Part/App/AppPartPy.cpp index 0103fbf6fb..87e36e6348 100644 --- a/src/Mod/Part/App/AppPartPy.cpp +++ b/src/Mod/Part/App/AppPartPy.cpp @@ -118,6 +118,14 @@ #include "ImportStep.h" #include "edgecluster.h" +#include +#include FT_FREETYPE_H +#include FT_OUTLINE_H +#include FT_GLYPH_H +#include FT_TYPES_H + +#include "FT2FC.h" + using Base::Console; using namespace Part; using namespace std; @@ -313,6 +321,59 @@ show(PyObject *self, PyObject *args) Py_Return; } +////// makeWireString ///////// +static PyObject * makeWireString(PyObject *self, PyObject *args) +{ + char* dir = "dDir"; //something is unhappy if these are uninit. not sure yet. + char* fontfile = "dFont"; + char* text = "dText"; + float height; + int track = 0; + std::string sdir,sfontfile,stext; + + std::vector > ret; + std::vector::iterator iWire; + std::vector >:: iterator iChar; + + PyObject *WireList, *CharList; +// not right for unicode strings. use format u? or O with check for ascii/ucs2(4)? + if (!PyArg_ParseTuple(args, "sssf|i", &text, + &dir, + &fontfile, + &height, + &track)) { + Base::Console().Message("** makeWireString bad args.\n"); + return NULL; + } + + try { + sdir = dir; + sfontfile = fontfile; + stext = text; + // ft2fc seems to work. let's leave it where it is for now while we get Py/FC internals working +// need to tell FT2FC if single byte or multi byte chars. + ret = FT2FC(stext,sdir,sfontfile,height,track); // get vector of wire chars +// int testret = TestSub(); + // if (ret not empty) + CharList = PyList_New(0); + for (iChar = ret.begin(); iChar !=ret.end(); ++iChar) { + WireList = PyList_New(0); + for (iWire = iChar->begin(); iWire != iChar->end(); ++iWire){ + PyObject* newobj = new TopoShapeWirePy(new TopoShape (*iWire)); + PyList_Append(WireList,newobj); + } + // if (list not empty) + PyList_Append(CharList,WireList); + } + return (CharList); + } + catch (Standard_DomainError) { + PyErr_SetString(PyExc_Exception, "makeWireString failed"); + return NULL; + } +} +/////// makeWireString ///////// + static PyObject * makeCompound(PyObject *self, PyObject *args) { @@ -1516,6 +1577,9 @@ struct PyMethodDef Part_methods[] = { {"makeLoft" ,makeLoft,METH_VARARGS, "makeLoft(list of wires) -- Create a loft shape."}, + + {"makeWireString" ,makeWireString ,METH_VARARGS, + "makeWireString(fontdir,fontfile,string,height,[track]) -- Make wires in the form of a string."}, {"cast_to_shape" ,cast_to_shape,METH_VARARGS, "cast_to_shape(shape) -- Cast to the actual shape type"}, diff --git a/src/Mod/Part/App/CMakeLists.txt b/src/Mod/Part/App/CMakeLists.txt index 079a52a3e5..74a0ef3206 100644 --- a/src/Mod/Part/App/CMakeLists.txt +++ b/src/Mod/Part/App/CMakeLists.txt @@ -14,12 +14,14 @@ include_directories( ${PYTHON_INCLUDE_PATH} ${XERCESC_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} + ${FREETYPE_INCLUDE_DIRS} ) link_directories(${OCC_LIBRARY_DIR}) set(Part_LIBS ${OCC_LIBRARIES} + ${FREETYPE_LIBRARY} FreeCADApp ) @@ -237,6 +239,8 @@ SET(Part_SRCS modelRefine.cpp modelRefine.h Tools.h + FT2FC.cpp + FT2FC.h ) SET(Part_Scripts diff --git a/src/Mod/Part/App/FT2FC.cpp b/src/Mod/Part/App/FT2FC.cpp new file mode 100644 index 0000000000..f4ac72f81e --- /dev/null +++ b/src/Mod/Part/App/FT2FC.cpp @@ -0,0 +1,323 @@ +#include +#include FT_FREETYPE_H +#include FT_OUTLINE_H +#include FT_GLYPH_H +#include FT_TYPES_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "FT2FC.h" + +// Private function prototypes +void getFTChar(char c); +std::vector getGlyphContours(); +FT_Vector getKerning(char lc, char rc); +TopoDS_Wire edgesToWire(std::vector Edges); + +bool DEBUG=true; + +struct FTDC_Ctx { // FT Decomp Context for 1 char + std::vector TWires; + std::vector Edges; + int ConCnt; + int SegCnt; + char currchar; + int penpos; + float scalefactor; + FT_Vector LastVert; + }; + +// Made a TopoDS_Wire from a list of TopoDS_Edges +TopoDS_Wire edgesToWire(std::vector Edges) { + TopoDS_Wire result; + std::vector::iterator iEdge; + // if Edges.empty() ???? + BRepBuilderAPI_MakeWire mkWire; + for (iEdge = Edges.begin(); iEdge != Edges.end(); ++iEdge){ + mkWire.Add(*iEdge); + } + // if(mkWire.Done()) ??? + result = mkWire.Wire(); + return(result); + } + +// FT Decompose callbacks and data defns +// move_cb called for start of new contour. pt is xy of contour start. +// p points to the context where we remember what happened previously (last point, etc) +static int move_cb(const FT_Vector* pt, void* p) { + FTDC_Ctx* dc = (FTDC_Ctx*) p; + dc->ConCnt++; + if (!dc->Edges.empty()){ // empty on first contour. (or messed up font) + TopoDS_Wire newwire; + newwire = edgesToWire(dc->Edges); + dc->TWires.push_back(newwire); + dc->Edges.clear(); + } + dc->LastVert.x = pt->x + dc->penpos; // move along baseline + dc->LastVert.y = pt->y; + return 0; + } + +// line_cb called for line segment in the current contour: line(LastVert -- pt) +static int line_cb(const FT_Vector* pt, void* p) { + FTDC_Ctx* dc = (FTDC_Ctx*) p; + // convert font coords to FC/OCC coords + float v1x = dc->scalefactor * dc->LastVert.x; // LastVert already moved along baseline + float v1y = dc->scalefactor * dc->LastVert.y; + float v2x = dc->scalefactor * (pt->x + dc->penpos); + float v2y = dc->scalefactor * pt->y; + gp_Pnt v1(v1x, v1y, 0); + gp_Pnt v2(v2x, v2y, 0); + BRepBuilderAPI_MakeEdge makeEdge(v1,v2); + TopoDS_Edge edge = makeEdge.Edge(); + dc->Edges.push_back(edge); + dc->SegCnt++; + dc->LastVert.x = pt->x + dc->penpos; + dc->LastVert.y = pt->y; + return 0; + } +// quad_cb called for quadratic (conic) BCurve segment in the current contour +// (ie V-C-V in TTF fonts). BCurve(LastVert -- pt0 -- pt1) +static int quad_cb(const FT_Vector* pt0, const FT_Vector* pt1, void* p) { + FTDC_Ctx* dc = (FTDC_Ctx*) p; + TColgp_Array1OfPnt Poles(1,3); + // convert font coords to FC/OCC coords + float v1x = dc->scalefactor * dc->LastVert.x; + float v1y = dc->scalefactor * dc->LastVert.y; + float c1x = dc->scalefactor * (pt0->x + dc->penpos); + float c1y = dc->scalefactor * pt0->y; + float v2x = dc->scalefactor * (pt1->x + dc->penpos); + float v2y = dc->scalefactor * pt1->y; + gp_Pnt v1(v1x, v1y, 0); + gp_Pnt c1(c1x, c1y, 0); + gp_Pnt v2(v2x, v2y, 0); + Poles.SetValue(1, v1); + Poles.SetValue(2, c1); + Poles.SetValue(3, v2); + // "new" bcseg? need to free this, but don't know when! does edge need it forever? or just for creation? + // how to delete a "handle" (!= a pointer)? + Handle(Geom_BezierCurve) bcseg = new Geom_BezierCurve(Poles); + BRepBuilderAPI_MakeEdge makeEdge(bcseg, v1, v2); + TopoDS_Edge edge = makeEdge.Edge(); + dc->Edges.push_back(edge); + dc->SegCnt++; + dc->LastVert.x = pt1->x + dc->penpos; + dc->LastVert.y = pt1->y; + return 0; + } + +// cubic_cb called for cubic BCurve segment in the current contour (ie V-C-C-V in +// Type 1 fonts). BCurve(LastVert -- pt0 -- pt1 -- pt2) +static int cubic_cb(const FT_Vector* pt0, const FT_Vector* pt1, const FT_Vector* pt2, void* p) { + FTDC_Ctx* dc = (FTDC_Ctx*) p; + TColgp_Array1OfPnt Poles(1,4); + // convert font coords to FC/OCC coords + float v1x = dc->scalefactor * dc->LastVert.x; + float v1y = dc->scalefactor * dc->LastVert.y; + float c1x = dc->scalefactor * (pt0->x + dc->penpos); + float c1y = dc->scalefactor * pt0->y; + float c2x = dc->scalefactor * (pt1->x + dc->penpos); + float c2y = dc->scalefactor * pt1->y; + float v2x = dc->scalefactor * (pt2->x + dc->penpos); + float v2y = dc->scalefactor * pt2->y; + gp_Pnt v1(v1x, v1y, 0); + gp_Pnt c1(c1x, c1y, 0); + gp_Pnt c2(c2x, c2y, 0); + gp_Pnt v2(v2x, v2y, 0); + Poles.SetValue(1, v1); + Poles.SetValue(2, c1); + Poles.SetValue(3, c2); + Poles.SetValue(4, v2); + Handle(Geom_BezierCurve) bcseg = new Geom_BezierCurve(Poles); // new? need to free this + BRepBuilderAPI_MakeEdge makeEdge(bcseg, v1, v2); + TopoDS_Edge edge = makeEdge.Edge(); + dc->Edges.push_back(edge); + dc->SegCnt++; + dc->LastVert.x = pt2->x + dc->penpos; + dc->LastVert.y = pt2->y; + return 0; + } + +// FT Callbacks structure +static FT_Outline_Funcs outline_funcs = { + (FT_Outline_MoveToFunc)move_cb, + (FT_Outline_LineToFunc)line_cb, + (FT_Outline_ConicToFunc)quad_cb, + (FT_Outline_CubicToFunc)cubic_cb, + 0, 0 // device resolutions not needed + }; + +// load glyph outline into FTFont. return char's h-adv metric. +void getFTChar(FT_Face FTFont, char c) { + FT_Error error; + FT_UInt flags = FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP; + std::stringstream ErrorMsg; + + error = FT_Load_Char(FTFont, + c, + flags); + if(error) { + ErrorMsg << "FT_Load_Char failed: " << error; + throw std::runtime_error(ErrorMsg.str()); + } + return; + } + +// get kerning values for this char pair +//TODO: should check FT_HASKERNING flag +FT_Vector getKerning(FT_Face FTFont, char lc, char rc) { + FT_Vector retXY; + FT_Error error; + std::stringstream ErrorMsg; + FT_Vector ftKern; + FT_UInt lcx = FT_Get_Char_Index(FTFont, lc); + FT_UInt rcx = FT_Get_Char_Index(FTFont, rc); + error = FT_Get_Kerning(FTFont,lcx,rcx,FT_KERNING_DEFAULT,&ftKern); + if(error) { + ErrorMsg << "FT_Get_Kerning failed: " << error; + throw std::runtime_error(ErrorMsg.str()); + } + retXY.x = ftKern.x; + retXY.y = ftKern.y; + return(retXY); + } + +// get glyph outline for current char +std::vector getGlyphContours(FT_Face FTFont, char currchar, int PenPos, float Scale) { + FT_Error error = 0; + std::stringstream ErrorMsg; + FT_Outline* FTOPointer; + FTDC_Ctx ctx; + FTOPointer = &FTFont->glyph->outline; + + ctx.ConCnt = 0; + ctx.SegCnt = 0; + ctx.currchar = currchar; + ctx.penpos = PenPos; + ctx.scalefactor = Scale; + ctx.Edges.clear(); + ctx.TWires.clear(); + + error = FT_Outline_Decompose(FTOPointer, &outline_funcs, &ctx); + if(error) { + ErrorMsg << "FT_Decompose failed: " << error; + throw std::runtime_error(ErrorMsg.str()); + } + if (DEBUG) + std::cout << "getGlyphContours processed char: " << currchar << " with " << ctx.ConCnt << + " contours containing " << ctx.SegCnt << " segments." << std::endl; + + if (!ctx.Edges.empty()){ // make the last twire + TopoDS_Wire newwire; + newwire = edgesToWire(ctx.Edges); + ctx.TWires.push_back(newwire); + } + return(ctx.TWires); + } + +// get string's wires (contours) in FC/OCC coords +std::vector > FT2FC(const std::string shapestring, + const std::string FontPath, + const std::string FontName, + const float stringheight, // in fc coords + const int tracking) { // in fc coords + FT_Library FTLib; + FT_Face FTFont; + FT_Error error; + FT_Long FaceIndex; + FT_Vector kern; + std::string FontSpec; + std::stringstream ErrorMsg; + + float scalefactor; + char prevchar,currchar; + int cadv,PenPos; + size_t i; + std::vector CharWires; + std::vector > RetString; + + std::cout << "FT2FC started: "<< FontPath << std::endl; + + + error = FT_Init_FreeType(&FTLib); + if(error) { + ErrorMsg << "FT_Init_FreeType failed: " << error; + throw std::runtime_error(ErrorMsg.str()); + } + FontSpec = FontPath + FontName; + FaceIndex = 0; // some fonts have multiple faces + // NOTE: FT blows up if font file not found. It does not return an error!!! + std::ifstream is; + is.open (FontSpec.c_str()); + if (!is) { + ErrorMsg << "Font file not found: " << FontSpec; + throw std::runtime_error(ErrorMsg.str()); + } + // maybe boost::filesystem::exists for x-platform?? + error = FT_New_Face(FTLib,FontSpec.c_str(),FaceIndex, &FTFont); + if(error) { + ErrorMsg << "FT_New_Face failed: " << error; + throw std::runtime_error(ErrorMsg.str()); + } +//TODO: check that FTFont is scalable. + +// FT2 blows up if char size is not set to some non-zero value. +// This sets size to 48 point. Magic. + error = FT_Set_Char_Size(FTFont, + 0, /* char_width in 1/64th of points */ + 48*64, /* char_height in 1/64th of points */ + 0, /* horizontal device resolution */ + 0 ); /* vertical device resolution */ + if(error) { + ErrorMsg << "FT_Set_Char_Size failed: " << error; + throw std::runtime_error(ErrorMsg.str()); + } + + prevchar = 0; + PenPos = 0; + scalefactor = float(stringheight/FTFont->height); + for (i=0;iglyph->advance.x; + kern = getKerning(FTFont,prevchar,currchar); + PenPos += kern.x; + CharWires = getGlyphContours(FTFont,currchar,PenPos, scalefactor); + if (CharWires.empty()) // whitespace char + std::cout << "Char " << i << " = " << currchar << " has no wires! " << std::endl; + else + RetString.push_back(CharWires); + // not entirely happy with tracking solution. It's specified in FC units, + // so we have to convert back to font units to use it here. We could + // lose some accuracy. Hard to put it into FT callbacks since tracking + // only affects position of chars 2 - n. + PenPos += cadv + int(tracking/scalefactor); + prevchar = currchar; + } + + error = FT_Done_FreeType(FTLib); + if(error) { + ErrorMsg << "FT_Done_FreeType failed: " << error; + throw std::runtime_error(ErrorMsg.str()); + } + + return(RetString); + } + diff --git a/src/Mod/Part/App/FT2FC.h b/src/Mod/Part/App/FT2FC.h new file mode 100644 index 0000000000..a843a4c4a2 --- /dev/null +++ b/src/Mod/Part/App/FT2FC.h @@ -0,0 +1,12 @@ +// Public header for FT2FC.cpp + +#ifndef FT2FC_H +#define FT2FC_H +// public function +std::vector > FT2FC(const std::string shapestring, + const std::string FontPath, + const std::string FontName, + const float stringheight, + const int tracking); +#endif // FT2FC_H + From d030445d39c7fb70e82f86f88f7da55172c62175 Mon Sep 17 00:00:00 2001 From: WandererFan Date: Mon, 18 Mar 2013 18:05:38 -0400 Subject: [PATCH 2/9] Handle Py_UNICODE objects & ASCII Py_Strings --- src/Mod/Part/App/AppPartPy.cpp | 80 +++++++++++++++++++++++----------- src/Mod/Part/App/FT2FC.cpp | 65 +++++++++++++++++++++------ src/Mod/Part/App/FT2FC.h | 11 ++++- 3 files changed, 114 insertions(+), 42 deletions(-) diff --git a/src/Mod/Part/App/AppPartPy.cpp b/src/Mod/Part/App/AppPartPy.cpp index 87e36e6348..62df05c392 100644 --- a/src/Mod/Part/App/AppPartPy.cpp +++ b/src/Mod/Part/App/AppPartPy.cpp @@ -324,9 +324,10 @@ show(PyObject *self, PyObject *args) ////// makeWireString ///////// static PyObject * makeWireString(PyObject *self, PyObject *args) { - char* dir = "dDir"; //something is unhappy if these are uninit. not sure yet. + char* dir = "dDir"; //something is unhappy if these are uninit. not sure why yet. char* fontfile = "dFont"; char* text = "dText"; + const char* ctext = "cText"; float height; int track = 0; std::string sdir,sfontfile,stext; @@ -335,9 +336,10 @@ static PyObject * makeWireString(PyObject *self, PyObject *args) std::vector::iterator iWire; std::vector >:: iterator iChar; - PyObject *WireList, *CharList; -// not right for unicode strings. use format u? or O with check for ascii/ucs2(4)? - if (!PyArg_ParseTuple(args, "sssf|i", &text, + PyObject *WireList, *CharList, *intext; + Py_UNICODE *unichars; +// fixing unicode issues? + if (!PyArg_ParseTuple(args, "Ossf|i", &intext, &dir, &fontfile, &height, @@ -345,32 +347,58 @@ static PyObject * makeWireString(PyObject *self, PyObject *args) Base::Console().Message("** makeWireString bad args.\n"); return NULL; } - - try { - sdir = dir; - sfontfile = fontfile; - stext = text; - // ft2fc seems to work. let's leave it where it is for now while we get Py/FC internals working -// need to tell FT2FC if single byte or multi byte chars. - ret = FT2FC(stext,sdir,sfontfile,height,track); // get vector of wire chars -// int testret = TestSub(); - // if (ret not empty) - CharList = PyList_New(0); - for (iChar = ret.begin(); iChar !=ret.end(); ++iChar) { - WireList = PyList_New(0); - for (iWire = iChar->begin(); iWire != iChar->end(); ++iWire){ - PyObject* newobj = new TopoShapeWirePy(new TopoShape (*iWire)); - PyList_Append(WireList,newobj); - } - // if (list not empty) - PyList_Append(CharList,WireList); +// !@##$$%&^ unicode + if (PyString_Check(intext)) { + Base::Console().Message("** makeWireString obj is pystring.\n"); +// call c-string version + try { + text = PyString_AsString(intext); + int strsize = strlen(text); + Base::Console().Message("** makeWireString pystring len: %d\n", strsize); + sdir = dir; + sfontfile = fontfile; +// stext = text; + ret = FT2FCc(text,sdir,sfontfile,height,track); // get vector of wire chars + } + catch (Standard_DomainError) { + PyErr_SetString(PyExc_Exception, "makeWireString failed 1"); + return NULL; } - return (CharList); } - catch (Standard_DomainError) { - PyErr_SetString(PyExc_Exception, "makeWireString failed"); + else if (PyUnicode_Check(intext)) { + Base::Console().Message("** makeWireString obj is unicode.\n"); +// call ucs-2/4 version (Py_UNICODE object) + try { + Py_ssize_t pysize = PyUnicode_GetSize(intext); + unichars = PyUnicode_AS_UNICODE(intext); +// text = const_cast (PyUnicode_AS_DATA(intext)); //kludge + Base::Console().Message("** makeWireString unicode len: %d\n", pysize); + sdir = dir; + sfontfile = fontfile; + ret = FT2FCpu(unichars,pysize,sdir,sfontfile,height,track); // get vector of wire chars + } + catch (Standard_DomainError) { + PyErr_SetString(PyExc_Exception, "makeWireString failed 2"); + return NULL; + } + } + else { + Base::Console().Message("** makeWireString bad string.\n"); return NULL; + } + + // if (ret not empty) + CharList = PyList_New(0); + for (iChar = ret.begin(); iChar !=ret.end(); ++iChar) { + WireList = PyList_New(0); + for (iWire = iChar->begin(); iWire != iChar->end(); ++iWire){ + PyObject* newobj = new TopoShapeWirePy(new TopoShape (*iWire)); + PyList_Append(WireList,newobj); + } + // if (list not empty) + PyList_Append(CharList,WireList); } + return (CharList); } /////// makeWireString ///////// diff --git a/src/Mod/Part/App/FT2FC.cpp b/src/Mod/Part/App/FT2FC.cpp index f4ac72f81e..3f21b56971 100644 --- a/src/Mod/Part/App/FT2FC.cpp +++ b/src/Mod/Part/App/FT2FC.cpp @@ -1,3 +1,5 @@ +#include "Python.h" + #include #include FT_FREETYPE_H #include FT_OUTLINE_H @@ -25,10 +27,13 @@ #include "FT2FC.h" +typedef unsigned long UNICHAR; // should be = Py_UNICODE?? +typedef std::vector > FT2FCRET; + // Private function prototypes -void getFTChar(char c); +void getFTChar(UNICHAR c); std::vector getGlyphContours(); -FT_Vector getKerning(char lc, char rc); +FT_Vector getKerning(UNICHAR lc, UNICHAR rc); TopoDS_Wire edgesToWire(std::vector Edges); bool DEBUG=true; @@ -38,7 +43,7 @@ struct FTDC_Ctx { // FT Decomp Context for 1 char std::vector Edges; int ConCnt; int SegCnt; - char currchar; + UNICHAR currchar; int penpos; float scalefactor; FT_Vector LastVert; @@ -145,7 +150,7 @@ static int cubic_cb(const FT_Vector* pt0, const FT_Vector* pt1, const FT_Vector* Poles.SetValue(2, c1); Poles.SetValue(3, c2); Poles.SetValue(4, v2); - Handle(Geom_BezierCurve) bcseg = new Geom_BezierCurve(Poles); // new? need to free this + Handle(Geom_BezierCurve) bcseg = new Geom_BezierCurve(Poles); // new? need to free this? BRepBuilderAPI_MakeEdge makeEdge(bcseg, v1, v2); TopoDS_Edge edge = makeEdge.Edge(); dc->Edges.push_back(edge); @@ -165,7 +170,7 @@ static FT_Outline_Funcs outline_funcs = { }; // load glyph outline into FTFont. return char's h-adv metric. -void getFTChar(FT_Face FTFont, char c) { +void getFTChar(FT_Face FTFont, UNICHAR c) { FT_Error error; FT_UInt flags = FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP; std::stringstream ErrorMsg; @@ -182,7 +187,7 @@ void getFTChar(FT_Face FTFont, char c) { // get kerning values for this char pair //TODO: should check FT_HASKERNING flag -FT_Vector getKerning(FT_Face FTFont, char lc, char rc) { +FT_Vector getKerning(FT_Face FTFont, UNICHAR lc, UNICHAR rc) { FT_Vector retXY; FT_Error error; std::stringstream ErrorMsg; @@ -200,7 +205,7 @@ FT_Vector getKerning(FT_Face FTFont, char lc, char rc) { } // get glyph outline for current char -std::vector getGlyphContours(FT_Face FTFont, char currchar, int PenPos, float Scale) { +std::vector getGlyphContours(FT_Face FTFont, UNICHAR currchar, int PenPos, float Scale) { FT_Error error = 0; std::stringstream ErrorMsg; FT_Outline* FTOPointer; @@ -233,7 +238,8 @@ std::vector getGlyphContours(FT_Face FTFont, char currchar, int Pen } // get string's wires (contours) in FC/OCC coords -std::vector > FT2FC(const std::string shapestring, +//std::vector > FT2FC(const std::string shapestring, +FT2FCRET _FT2FC(const std::vector stringvec, const std::string FontPath, const std::string FontName, const float stringheight, // in fc coords @@ -247,11 +253,11 @@ std::vector > FT2FC(const std::string shapestring, std::stringstream ErrorMsg; float scalefactor; - char prevchar,currchar; + UNICHAR prevchar,currchar; int cadv,PenPos; - size_t i; + size_t i, length; std::vector CharWires; - std::vector > RetString; + FT2FCRET RetString; std::cout << "FT2FC started: "<< FontPath << std::endl; @@ -293,15 +299,18 @@ std::vector > FT2FC(const std::string shapestring, prevchar = 0; PenPos = 0; scalefactor = float(stringheight/FTFont->height); - for (i=0;iglyph->advance.x; kern = getKerning(FTFont,prevchar,currchar); PenPos += kern.x; CharWires = getGlyphContours(FTFont,currchar,PenPos, scalefactor); if (CharWires.empty()) // whitespace char - std::cout << "Char " << i << " = " << currchar << " has no wires! " << std::endl; + std::cout << "char " << i << " = " << hex << std::showbase << currchar << " has no wires! " << std::endl; else RetString.push_back(CharWires); // not entirely happy with tracking solution. It's specified in FC units, @@ -320,4 +329,32 @@ std::vector > FT2FC(const std::string shapestring, return(RetString); } + +FT2FCRET FT2FCc(const char *cstring, + const std::string FontPath, + const std::string FontName, + const float stringheight, // in fc coords + const int tracking) { // in fc coords) + size_t i, length; + length = strlen(cstring); + std::vector stringvec(length, 0); + for (i=0;i stringvec(length, 0); + for (i=0;i > FT2FC(const std::string shapestring, +// public functions +std::vector > FT2FCc(const char *cstring, const std::string FontPath, const std::string FontName, const float stringheight, const int tracking); +std::vector > FT2FCpu(const Py_UNICODE *unichars, +//std::vector > FT2FCpu(const char16_t *unichars, + const size_t length, + const std::string FontPath, + const std::string FontName, + const float stringheight, + const int tracking); #endif // FT2FC_H From 88d037f26e9373797aafc49039f6890d0adde947 Mon Sep 17 00:00:00 2001 From: WandererFan Date: Tue, 19 Mar 2013 13:20:12 -0400 Subject: [PATCH 3/9] Handle UTF-8 in Py strings. --- src/Mod/Part/App/AppPartPy.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/Mod/Part/App/AppPartPy.cpp b/src/Mod/Part/App/AppPartPy.cpp index 62df05c392..3f39bab76c 100644 --- a/src/Mod/Part/App/AppPartPy.cpp +++ b/src/Mod/Part/App/AppPartPy.cpp @@ -338,6 +338,7 @@ static PyObject * makeWireString(PyObject *self, PyObject *args) PyObject *WireList, *CharList, *intext; Py_UNICODE *unichars; + Py_ssize_t pysize; // fixing unicode issues? if (!PyArg_ParseTuple(args, "Ossf|i", &intext, &dir, @@ -353,12 +354,24 @@ static PyObject * makeWireString(PyObject *self, PyObject *args) // call c-string version try { text = PyString_AsString(intext); - int strsize = strlen(text); - Base::Console().Message("** makeWireString pystring len: %d\n", strsize); + Base::Console().Message("** makeWireString pystring => text:<%s>\n", text); // ??? +// int strsize = strlen(text); +// pysize = PyString_Size(intext); + PyObject *p = Base::PyAsUnicodeObject(text); + if (!p) { + Base::Console().Message("** makeWireString Base::PyAsUnicode returns NULL.\n"); + return NULL; + } + pysize = PyUnicode_GetSize(p); +// PyObject *p = PyUnicode_DecodeUTF8(text,pysize,0); + unichars = PyUnicode_AS_UNICODE(p); +// PyObject *PyUnicode_FromString(const char *u)¶ + Base::Console().Message("** makeWireString pystring len: %d\n", pysize); sdir = dir; sfontfile = fontfile; // stext = text; - ret = FT2FCc(text,sdir,sfontfile,height,track); // get vector of wire chars +// ret = FT2FCc(text,sdir,sfontfile,height,track); // get vector of wire chars + ret = FT2FCpu(unichars,pysize,sdir,sfontfile,height,track); // get vector of wire chars } catch (Standard_DomainError) { PyErr_SetString(PyExc_Exception, "makeWireString failed 1"); From 9c5608d8d283fcdb2f81eaa801a47af9379b5f19 Mon Sep 17 00:00:00 2001 From: WandererFan Date: Wed, 20 Mar 2013 08:12:46 -0400 Subject: [PATCH 4/9] Unicode cleanup. --- src/Mod/Part/App/AppPartPy.cpp | 46 +++++++++++---------------- src/Mod/Part/App/FT2FC.cpp | 57 ++++++++++++++++------------------ src/Mod/Part/App/FT2FC.h | 5 ++- 3 files changed, 46 insertions(+), 62 deletions(-) diff --git a/src/Mod/Part/App/AppPartPy.cpp b/src/Mod/Part/App/AppPartPy.cpp index 3f39bab76c..3ae4dc95e4 100644 --- a/src/Mod/Part/App/AppPartPy.cpp +++ b/src/Mod/Part/App/AppPartPy.cpp @@ -321,16 +321,15 @@ show(PyObject *self, PyObject *args) Py_Return; } -////// makeWireString ///////// static PyObject * makeWireString(PyObject *self, PyObject *args) { - char* dir = "dDir"; //something is unhappy if these are uninit. not sure why yet. - char* fontfile = "dFont"; - char* text = "dText"; - const char* ctext = "cText"; + const char* dir; + const char* fontfile; + const char* text; float height; int track = 0; - std::string sdir,sfontfile,stext; + + std::string sdir,sfontfile; std::vector > ret; std::vector::iterator iWire; @@ -339,7 +338,7 @@ static PyObject * makeWireString(PyObject *self, PyObject *args) PyObject *WireList, *CharList, *intext; Py_UNICODE *unichars; Py_ssize_t pysize; -// fixing unicode issues? + if (!PyArg_ParseTuple(args, "Ossf|i", &intext, &dir, &fontfile, @@ -348,29 +347,24 @@ static PyObject * makeWireString(PyObject *self, PyObject *args) Base::Console().Message("** makeWireString bad args.\n"); return NULL; } -// !@##$$%&^ unicode + + sdir = dir; // c string to std::string + sfontfile = fontfile; + if (PyString_Check(intext)) { - Base::Console().Message("** makeWireString obj is pystring.\n"); -// call c-string version +// Base::Console().Message("** makeWireString obj is pystring.\n"); +// handle c type string try { text = PyString_AsString(intext); - Base::Console().Message("** makeWireString pystring => text:<%s>\n", text); // ??? -// int strsize = strlen(text); -// pysize = PyString_Size(intext); +// Base::Console().Message("** makeWireString pystring => text:<%s>\n", text); PyObject *p = Base::PyAsUnicodeObject(text); if (!p) { Base::Console().Message("** makeWireString Base::PyAsUnicode returns NULL.\n"); - return NULL; + return NULL; } pysize = PyUnicode_GetSize(p); -// PyObject *p = PyUnicode_DecodeUTF8(text,pysize,0); unichars = PyUnicode_AS_UNICODE(p); -// PyObject *PyUnicode_FromString(const char *u)¶ - Base::Console().Message("** makeWireString pystring len: %d\n", pysize); - sdir = dir; - sfontfile = fontfile; -// stext = text; -// ret = FT2FCc(text,sdir,sfontfile,height,track); // get vector of wire chars +// Base::Console().Message("** makeWireString pystring len: %d\n", pysize); ret = FT2FCpu(unichars,pysize,sdir,sfontfile,height,track); // get vector of wire chars } catch (Standard_DomainError) { @@ -379,15 +373,12 @@ static PyObject * makeWireString(PyObject *self, PyObject *args) } } else if (PyUnicode_Check(intext)) { - Base::Console().Message("** makeWireString obj is unicode.\n"); -// call ucs-2/4 version (Py_UNICODE object) +// Base::Console().Message("** makeWireString obj is unicode.\n"); +// handle ucs-2/4 version (Py_UNICODE object) try { Py_ssize_t pysize = PyUnicode_GetSize(intext); unichars = PyUnicode_AS_UNICODE(intext); -// text = const_cast (PyUnicode_AS_DATA(intext)); //kludge - Base::Console().Message("** makeWireString unicode len: %d\n", pysize); - sdir = dir; - sfontfile = fontfile; +// Base::Console().Message("** makeWireString unicode len: %d\n", pysize); ret = FT2FCpu(unichars,pysize,sdir,sfontfile,height,track); // get vector of wire chars } catch (Standard_DomainError) { @@ -413,7 +404,6 @@ static PyObject * makeWireString(PyObject *self, PyObject *args) } return (CharList); } -/////// makeWireString ///////// static PyObject * makeCompound(PyObject *self, PyObject *args) diff --git a/src/Mod/Part/App/FT2FC.cpp b/src/Mod/Part/App/FT2FC.cpp index 3f21b56971..632d8c4e06 100644 --- a/src/Mod/Part/App/FT2FC.cpp +++ b/src/Mod/Part/App/FT2FC.cpp @@ -1,4 +1,5 @@ -#include "Python.h" +//$$INSERT legal.txt +#include #include #include FT_FREETYPE_H @@ -27,7 +28,7 @@ #include "FT2FC.h" -typedef unsigned long UNICHAR; // should be = Py_UNICODE?? +typedef unsigned long UNICHAR; // should be = Py_UNICODE?? ul is FT2's codepoint type typedef std::vector > FT2FCRET; // Private function prototypes @@ -36,13 +37,13 @@ std::vector getGlyphContours(); FT_Vector getKerning(UNICHAR lc, UNICHAR rc); TopoDS_Wire edgesToWire(std::vector Edges); -bool DEBUG=true; +//bool DEBUG=true; struct FTDC_Ctx { // FT Decomp Context for 1 char std::vector TWires; std::vector Edges; - int ConCnt; - int SegCnt; +// int ConCnt; +// int SegCnt; UNICHAR currchar; int penpos; float scalefactor; @@ -68,7 +69,7 @@ TopoDS_Wire edgesToWire(std::vector Edges) { // p points to the context where we remember what happened previously (last point, etc) static int move_cb(const FT_Vector* pt, void* p) { FTDC_Ctx* dc = (FTDC_Ctx*) p; - dc->ConCnt++; +// dc->ConCnt++; if (!dc->Edges.empty()){ // empty on first contour. (or messed up font) TopoDS_Wire newwire; newwire = edgesToWire(dc->Edges); @@ -93,7 +94,7 @@ static int line_cb(const FT_Vector* pt, void* p) { BRepBuilderAPI_MakeEdge makeEdge(v1,v2); TopoDS_Edge edge = makeEdge.Edge(); dc->Edges.push_back(edge); - dc->SegCnt++; +// dc->SegCnt++; dc->LastVert.x = pt->x + dc->penpos; dc->LastVert.y = pt->y; return 0; @@ -116,13 +117,13 @@ static int quad_cb(const FT_Vector* pt0, const FT_Vector* pt1, void* p) { Poles.SetValue(1, v1); Poles.SetValue(2, c1); Poles.SetValue(3, v2); - // "new" bcseg? need to free this, but don't know when! does edge need it forever? or just for creation? - // how to delete a "handle" (!= a pointer)? + // "new" bcseg? need to free this, but don't know when! does makeedge need it forever? or just for creation? + // how to delete a "handle"? Handle(Geom_BezierCurve) bcseg = new Geom_BezierCurve(Poles); BRepBuilderAPI_MakeEdge makeEdge(bcseg, v1, v2); TopoDS_Edge edge = makeEdge.Edge(); dc->Edges.push_back(edge); - dc->SegCnt++; +// dc->SegCnt++; dc->LastVert.x = pt1->x + dc->penpos; dc->LastVert.y = pt1->y; return 0; @@ -154,7 +155,7 @@ static int cubic_cb(const FT_Vector* pt0, const FT_Vector* pt1, const FT_Vector* BRepBuilderAPI_MakeEdge makeEdge(bcseg, v1, v2); TopoDS_Edge edge = makeEdge.Edge(); dc->Edges.push_back(edge); - dc->SegCnt++; +// dc->SegCnt++; dc->LastVert.x = pt2->x + dc->penpos; dc->LastVert.y = pt2->y; return 0; @@ -166,10 +167,10 @@ static FT_Outline_Funcs outline_funcs = { (FT_Outline_LineToFunc)line_cb, (FT_Outline_ConicToFunc)quad_cb, (FT_Outline_CubicToFunc)cubic_cb, - 0, 0 // device resolutions not needed + 0, 0 // not needed for FC }; -// load glyph outline into FTFont. return char's h-adv metric. +// load glyph outline into FTFont. void getFTChar(FT_Face FTFont, UNICHAR c) { FT_Error error; FT_UInt flags = FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP; @@ -212,8 +213,8 @@ std::vector getGlyphContours(FT_Face FTFont, UNICHAR currchar, int FTDC_Ctx ctx; FTOPointer = &FTFont->glyph->outline; - ctx.ConCnt = 0; - ctx.SegCnt = 0; +// ctx.ConCnt = 0; +// ctx.SegCnt = 0; ctx.currchar = currchar; ctx.penpos = PenPos; ctx.scalefactor = Scale; @@ -225,9 +226,6 @@ std::vector getGlyphContours(FT_Face FTFont, UNICHAR currchar, int ErrorMsg << "FT_Decompose failed: " << error; throw std::runtime_error(ErrorMsg.str()); } - if (DEBUG) - std::cout << "getGlyphContours processed char: " << currchar << " with " << ctx.ConCnt << - " contours containing " << ctx.SegCnt << " segments." << std::endl; if (!ctx.Edges.empty()){ // make the last twire TopoDS_Wire newwire; @@ -238,7 +236,6 @@ std::vector getGlyphContours(FT_Face FTFont, UNICHAR currchar, int } // get string's wires (contours) in FC/OCC coords -//std::vector > FT2FC(const std::string shapestring, FT2FCRET _FT2FC(const std::vector stringvec, const std::string FontPath, const std::string FontName, @@ -257,10 +254,9 @@ FT2FCRET _FT2FC(const std::vector stringvec, int cadv,PenPos; size_t i, length; std::vector CharWires; - FT2FCRET RetString; + FT2FCRET Ret; - std::cout << "FT2FC started: "<< FontPath << std::endl; - +// std::cout << "FT2FC started: "<< FontPath << std::endl; error = FT_Init_FreeType(&FTLib); if(error) { @@ -269,6 +265,7 @@ FT2FCRET _FT2FC(const std::vector stringvec, } FontSpec = FontPath + FontName; FaceIndex = 0; // some fonts have multiple faces + // NOTE: FT blows up if font file not found. It does not return an error!!! std::ifstream is; is.open (FontSpec.c_str()); @@ -277,6 +274,7 @@ FT2FCRET _FT2FC(const std::vector stringvec, throw std::runtime_error(ErrorMsg.str()); } // maybe boost::filesystem::exists for x-platform?? + error = FT_New_Face(FTLib,FontSpec.c_str(),FaceIndex, &FTFont); if(error) { ErrorMsg << "FT_New_Face failed: " << error; @@ -300,8 +298,6 @@ FT2FCRET _FT2FC(const std::vector stringvec, PenPos = 0; scalefactor = float(stringheight/FTFont->height); length = stringvec.size(); -// for (i=0;i stringvec, if (CharWires.empty()) // whitespace char std::cout << "char " << i << " = " << hex << std::showbase << currchar << " has no wires! " << std::endl; else - RetString.push_back(CharWires); + Ret.push_back(CharWires); // not entirely happy with tracking solution. It's specified in FC units, // so we have to convert back to font units to use it here. We could // lose some accuracy. Hard to put it into FT callbacks since tracking @@ -327,29 +323,28 @@ FT2FCRET _FT2FC(const std::vector stringvec, throw std::runtime_error(ErrorMsg.str()); } - return(RetString); + return(Ret); } - +/* FT2FCRET FT2FCc(const char *cstring, const std::string FontPath, const std::string FontName, const float stringheight, // in fc coords - const int tracking) { // in fc coords) + const int tracking) { // in fc coords size_t i, length; length = strlen(cstring); std::vector stringvec(length, 0); for (i=0;i stringvec(length, 0); for (i=0;i > FT2FCc(const char *cstring, +/*std::vector > FT2FCc(const char *cstring, const std::string FontPath, const std::string FontName, const float stringheight, - const int tracking); + const int tracking);*/ std::vector > FT2FCpu(const Py_UNICODE *unichars, -//std::vector > FT2FCpu(const char16_t *unichars, const size_t length, const std::string FontPath, const std::string FontName, From 6465e367ebd13adfe2013ab47e0656b8a624d07e Mon Sep 17 00:00:00 2001 From: WandererFan Date: Wed, 20 Mar 2013 19:12:53 -0400 Subject: [PATCH 5/9] Combine UCS2 & UTF-8 logic. --- src/Mod/Part/App/AppPartPy.cpp | 76 +++++++++++++++++----------------- src/Mod/Part/App/FT2FC.cpp | 18 ++++---- src/Mod/Part/App/FT2FC.h | 4 +- 3 files changed, 50 insertions(+), 48 deletions(-) diff --git a/src/Mod/Part/App/AppPartPy.cpp b/src/Mod/Part/App/AppPartPy.cpp index 3ae4dc95e4..6fafa1937e 100644 --- a/src/Mod/Part/App/AppPartPy.cpp +++ b/src/Mod/Part/App/AppPartPy.cpp @@ -118,11 +118,13 @@ #include "ImportStep.h" #include "edgecluster.h" +//needed in AppPartPy??? #include #include FT_FREETYPE_H #include FT_OUTLINE_H #include FT_GLYPH_H #include FT_TYPES_H +//?? #include "FT2FC.h" @@ -325,19 +327,22 @@ static PyObject * makeWireString(PyObject *self, PyObject *args) { const char* dir; const char* fontfile; - const char* text; float height; int track = 0; - - std::string sdir,sfontfile; + + const char* text; + PyObject *intext; + + Py_UNICODE *unichars; + Py_ssize_t pysize; + +// std::string sdir,sfontfile; std::vector > ret; std::vector::iterator iWire; std::vector >:: iterator iChar; - PyObject *WireList, *CharList, *intext; - Py_UNICODE *unichars; - Py_ssize_t pysize; + PyObject *WireList, *CharList; if (!PyArg_ParseTuple(args, "Ossf|i", &intext, &dir, @@ -348,46 +353,39 @@ static PyObject * makeWireString(PyObject *self, PyObject *args) return NULL; } - sdir = dir; // c string to std::string - sfontfile = fontfile; - +// sdir = dir; // c string to std::string +// sfontfile = fontfile; + if (PyString_Check(intext)) { -// Base::Console().Message("** makeWireString obj is pystring.\n"); // handle c type string - try { - text = PyString_AsString(intext); -// Base::Console().Message("** makeWireString pystring => text:<%s>\n", text); - PyObject *p = Base::PyAsUnicodeObject(text); - if (!p) { - Base::Console().Message("** makeWireString Base::PyAsUnicode returns NULL.\n"); - return NULL; + PyObject *p = Base::PyAsUnicodeObject(PyString_AsString(intext)); //ascii/utf8 to PyUni + if (!p) { + Base::Console().Message("** makeWireString can't convert PyString.\n"); + return NULL; } - pysize = PyUnicode_GetSize(p); - unichars = PyUnicode_AS_UNICODE(p); -// Base::Console().Message("** makeWireString pystring len: %d\n", pysize); - ret = FT2FCpu(unichars,pysize,sdir,sfontfile,height,track); // get vector of wire chars + pysize = PyUnicode_GetSize(p); + unichars = PyUnicode_AS_UNICODE(p); } - catch (Standard_DomainError) { - PyErr_SetString(PyExc_Exception, "makeWireString failed 1"); - return NULL; - } - } else if (PyUnicode_Check(intext)) { -// Base::Console().Message("** makeWireString obj is unicode.\n"); -// handle ucs-2/4 version (Py_UNICODE object) - try { - Py_ssize_t pysize = PyUnicode_GetSize(intext); - unichars = PyUnicode_AS_UNICODE(intext); -// Base::Console().Message("** makeWireString unicode len: %d\n", pysize); - ret = FT2FCpu(unichars,pysize,sdir,sfontfile,height,track); // get vector of wire chars - } - catch (Standard_DomainError) { - PyErr_SetString(PyExc_Exception, "makeWireString failed 2"); - return NULL; - } +// handle ucs-2/4 input (Py_UNICODE object) + pysize = PyUnicode_GetSize(intext); +// Base::Console().Message("** makeWireString intext is Unicode len: '%d'.\n", pysize); + unichars = PyUnicode_AS_UNICODE(intext); } else { - Base::Console().Message("** makeWireString bad string.\n"); + Base::Console().Message("** makeWireString bad text parameter.\n"); + return NULL; + } + + try { + ret = FT2FCpu(unichars,pysize,dir,fontfile,height,track); // get vector of wire chars + } + catch (Standard_DomainError) { // Standard_DomainError is OCC error. + PyErr_SetString(PyExc_Exception, "makeWireString failed - OCC"); + return NULL; + } + catch (std::runtime_error& e) { // FT2 or FT2FC errors + PyErr_SetString(PyExc_Exception, e.what()); return NULL; } diff --git a/src/Mod/Part/App/FT2FC.cpp b/src/Mod/Part/App/FT2FC.cpp index 632d8c4e06..ab0bdbb19d 100644 --- a/src/Mod/Part/App/FT2FC.cpp +++ b/src/Mod/Part/App/FT2FC.cpp @@ -187,7 +187,7 @@ void getFTChar(FT_Face FTFont, UNICHAR c) { } // get kerning values for this char pair -//TODO: should check FT_HASKERNING flag +//TODO: should check FT_HASKERNING flag? FT_Vector getKerning(FT_Face FTFont, UNICHAR lc, UNICHAR rc) { FT_Vector retXY; FT_Error error; @@ -237,8 +237,8 @@ std::vector getGlyphContours(FT_Face FTFont, UNICHAR currchar, int // get string's wires (contours) in FC/OCC coords FT2FCRET _FT2FC(const std::vector stringvec, - const std::string FontPath, - const std::string FontName, + const char * FontPath, + const char * FontName, const float stringheight, // in fc coords const int tracking) { // in fc coords FT_Library FTLib; @@ -263,7 +263,11 @@ FT2FCRET _FT2FC(const std::vector stringvec, ErrorMsg << "FT_Init_FreeType failed: " << error; throw std::runtime_error(ErrorMsg.str()); } - FontSpec = FontPath + FontName; + + std::string tmpPath = FontPath; // can't concat const char* + std::string tmpName = FontName; + FontSpec = tmpPath + tmpName; + FaceIndex = 0; // some fonts have multiple faces // NOTE: FT blows up if font file not found. It does not return an error!!! @@ -280,7 +284,7 @@ FT2FCRET _FT2FC(const std::vector stringvec, ErrorMsg << "FT_New_Face failed: " << error; throw std::runtime_error(ErrorMsg.str()); } -//TODO: check that FTFont is scalable. +//TODO: check that FTFont is scalable? // FT2 blows up if char size is not set to some non-zero value. // This sets size to 48 point. Magic. @@ -341,8 +345,8 @@ FT2FCRET FT2FCc(const char *cstring, FT2FCRET FT2FCpu(const Py_UNICODE *pustring, const size_t length, - const std::string FontPath, - const std::string FontName, + const char *FontPath, + const char *FontName, const float stringheight, // in fc coords const int tracking) { // in fc coords size_t i; diff --git a/src/Mod/Part/App/FT2FC.h b/src/Mod/Part/App/FT2FC.h index 2d5a325f8e..3475d20742 100644 --- a/src/Mod/Part/App/FT2FC.h +++ b/src/Mod/Part/App/FT2FC.h @@ -10,8 +10,8 @@ const int tracking);*/ std::vector > FT2FCpu(const Py_UNICODE *unichars, const size_t length, - const std::string FontPath, - const std::string FontName, + const char *FontPath, + const char *FontName, const float stringheight, const int tracking); #endif // FT2FC_H From da8b6d4a818c8f8198039efc1684d5510335db12 Mon Sep 17 00:00:00 2001 From: WandererFan Date: Wed, 20 Mar 2013 19:39:03 -0400 Subject: [PATCH 6/9] Eliminate temporary vector in FT2FC. --- src/Mod/Part/App/AppPartPy.cpp | 8 +---- src/Mod/Part/App/FT2FC.cpp | 55 +++++++++++++--------------------- src/Mod/Part/App/FT2FC.h | 9 ++---- 3 files changed, 24 insertions(+), 48 deletions(-) diff --git a/src/Mod/Part/App/AppPartPy.cpp b/src/Mod/Part/App/AppPartPy.cpp index 6fafa1937e..2d3b5db8ef 100644 --- a/src/Mod/Part/App/AppPartPy.cpp +++ b/src/Mod/Part/App/AppPartPy.cpp @@ -336,8 +336,6 @@ static PyObject * makeWireString(PyObject *self, PyObject *args) Py_UNICODE *unichars; Py_ssize_t pysize; -// std::string sdir,sfontfile; - std::vector > ret; std::vector::iterator iWire; std::vector >:: iterator iChar; @@ -352,9 +350,6 @@ static PyObject * makeWireString(PyObject *self, PyObject *args) Base::Console().Message("** makeWireString bad args.\n"); return NULL; } - -// sdir = dir; // c string to std::string -// sfontfile = fontfile; if (PyString_Check(intext)) { // handle c type string @@ -369,7 +364,6 @@ static PyObject * makeWireString(PyObject *self, PyObject *args) else if (PyUnicode_Check(intext)) { // handle ucs-2/4 input (Py_UNICODE object) pysize = PyUnicode_GetSize(intext); -// Base::Console().Message("** makeWireString intext is Unicode len: '%d'.\n", pysize); unichars = PyUnicode_AS_UNICODE(intext); } else { @@ -378,7 +372,7 @@ static PyObject * makeWireString(PyObject *self, PyObject *args) } try { - ret = FT2FCpu(unichars,pysize,dir,fontfile,height,track); // get vector of wire chars + ret = FT2FC(unichars,pysize,dir,fontfile,height,track); // get vector of wire chars } catch (Standard_DomainError) { // Standard_DomainError is OCC error. PyErr_SetString(PyExc_Exception, "makeWireString failed - OCC"); diff --git a/src/Mod/Part/App/FT2FC.cpp b/src/Mod/Part/App/FT2FC.cpp index ab0bdbb19d..7ab73a76c8 100644 --- a/src/Mod/Part/App/FT2FC.cpp +++ b/src/Mod/Part/App/FT2FC.cpp @@ -37,13 +37,9 @@ std::vector getGlyphContours(); FT_Vector getKerning(UNICHAR lc, UNICHAR rc); TopoDS_Wire edgesToWire(std::vector Edges); -//bool DEBUG=true; - struct FTDC_Ctx { // FT Decomp Context for 1 char std::vector TWires; std::vector Edges; -// int ConCnt; -// int SegCnt; UNICHAR currchar; int penpos; float scalefactor; @@ -69,7 +65,6 @@ TopoDS_Wire edgesToWire(std::vector Edges) { // p points to the context where we remember what happened previously (last point, etc) static int move_cb(const FT_Vector* pt, void* p) { FTDC_Ctx* dc = (FTDC_Ctx*) p; -// dc->ConCnt++; if (!dc->Edges.empty()){ // empty on first contour. (or messed up font) TopoDS_Wire newwire; newwire = edgesToWire(dc->Edges); @@ -94,7 +89,6 @@ static int line_cb(const FT_Vector* pt, void* p) { BRepBuilderAPI_MakeEdge makeEdge(v1,v2); TopoDS_Edge edge = makeEdge.Edge(); dc->Edges.push_back(edge); -// dc->SegCnt++; dc->LastVert.x = pt->x + dc->penpos; dc->LastVert.y = pt->y; return 0; @@ -123,7 +117,6 @@ static int quad_cb(const FT_Vector* pt0, const FT_Vector* pt1, void* p) { BRepBuilderAPI_MakeEdge makeEdge(bcseg, v1, v2); TopoDS_Edge edge = makeEdge.Edge(); dc->Edges.push_back(edge); -// dc->SegCnt++; dc->LastVert.x = pt1->x + dc->penpos; dc->LastVert.y = pt1->y; return 0; @@ -155,7 +148,6 @@ static int cubic_cb(const FT_Vector* pt0, const FT_Vector* pt1, const FT_Vector* BRepBuilderAPI_MakeEdge makeEdge(bcseg, v1, v2); TopoDS_Edge edge = makeEdge.Edge(); dc->Edges.push_back(edge); -// dc->SegCnt++; dc->LastVert.x = pt2->x + dc->penpos; dc->LastVert.y = pt2->y; return 0; @@ -236,11 +228,17 @@ std::vector getGlyphContours(FT_Face FTFont, UNICHAR currchar, int } // get string's wires (contours) in FC/OCC coords -FT2FCRET _FT2FC(const std::vector stringvec, +FT2FCRET FT2FC(const Py_UNICODE *pustring, + const size_t length, + const char *FontPath, + const char *FontName, + const float stringheight, // in fc coords + const int tracking) { // in fc coords +/*FT2FCRET _FT2FC(const std::vector stringvec, const char * FontPath, const char * FontName, const float stringheight, // in fc coords - const int tracking) { // in fc coords + const int tracking) { // in fc coords*/ FT_Library FTLib; FT_Face FTFont; FT_Error error; @@ -252,12 +250,11 @@ FT2FCRET _FT2FC(const std::vector stringvec, float scalefactor; UNICHAR prevchar,currchar; int cadv,PenPos; - size_t i, length; +// size_t i, length; + size_t i; std::vector CharWires; FT2FCRET Ret; -// std::cout << "FT2FC started: "<< FontPath << std::endl; - error = FT_Init_FreeType(&FTLib); if(error) { ErrorMsg << "FT_Init_FreeType failed: " << error; @@ -270,22 +267,23 @@ FT2FCRET _FT2FC(const std::vector stringvec, FaceIndex = 0; // some fonts have multiple faces - // NOTE: FT blows up if font file not found. It does not return an error!!! + // NOTE: FT does not return an error if font file not found. std::ifstream is; is.open (FontSpec.c_str()); if (!is) { ErrorMsg << "Font file not found: " << FontSpec; throw std::runtime_error(ErrorMsg.str()); } - // maybe boost::filesystem::exists for x-platform?? + // maybe boost::filesystem::exists for x-platform?? error = FT_New_Face(FTLib,FontSpec.c_str(),FaceIndex, &FTFont); if(error) { ErrorMsg << "FT_New_Face failed: " << error; throw std::runtime_error(ErrorMsg.str()); } -//TODO: check that FTFont is scalable? - + +//TODO: check that FTFont is scalable? only relevant for hinting etc? + // FT2 blows up if char size is not set to some non-zero value. // This sets size to 48 point. Magic. error = FT_Set_Char_Size(FTFont, @@ -301,9 +299,11 @@ FT2FCRET _FT2FC(const std::vector stringvec, prevchar = 0; PenPos = 0; scalefactor = float(stringheight/FTFont->height); - length = stringvec.size(); +// length = stringvec.size(); +// for (i=0;iglyph->advance.x; kern = getKerning(FTFont,prevchar,currchar); @@ -329,21 +329,8 @@ FT2FCRET _FT2FC(const std::vector stringvec, return(Ret); } -/* -FT2FCRET FT2FCc(const char *cstring, - const std::string FontPath, - const std::string FontName, - const float stringheight, // in fc coords - const int tracking) { // in fc coords - size_t i, length; - length = strlen(cstring); - std::vector stringvec(length, 0); - for (i=0;i > FT2FCc(const char *cstring, - const std::string FontPath, - const std::string FontName, - const float stringheight, - const int tracking);*/ -std::vector > FT2FCpu(const Py_UNICODE *unichars, +// public function +std::vector > FT2FC(const Py_UNICODE *unichars, const size_t length, const char *FontPath, const char *FontName, From b507f618bb40fb4a562ebf38628036e173c8b60c Mon Sep 17 00:00:00 2001 From: WandererFan Date: Thu, 21 Mar 2013 09:14:25 -0400 Subject: [PATCH 7/9] Refactor to move FC object creation from AppPartPy to FT2FC. --- src/Mod/Part/App/AppPartPy.cpp | 26 +++--- src/Mod/Part/App/FT2FC.cpp | 161 ++++++++++++++++----------------- src/Mod/Part/App/FT2FC.h | 3 +- 3 files changed, 88 insertions(+), 102 deletions(-) diff --git a/src/Mod/Part/App/AppPartPy.cpp b/src/Mod/Part/App/AppPartPy.cpp index 2d3b5db8ef..27b47c0a06 100644 --- a/src/Mod/Part/App/AppPartPy.cpp +++ b/src/Mod/Part/App/AppPartPy.cpp @@ -118,13 +118,13 @@ #include "ImportStep.h" #include "edgecluster.h" -//needed in AppPartPy??? +/*//needed in AppPartPy??? #include #include FT_FREETYPE_H #include FT_OUTLINE_H #include FT_GLYPH_H #include FT_TYPES_H -//?? +//??*/ #include "FT2FC.h" @@ -325,20 +325,19 @@ show(PyObject *self, PyObject *args) static PyObject * makeWireString(PyObject *self, PyObject *args) { + PyObject *intext; const char* dir; const char* fontfile; float height; int track = 0; const char* text; - PyObject *intext; - Py_UNICODE *unichars; Py_ssize_t pysize; - std::vector > ret; - std::vector::iterator iWire; - std::vector >:: iterator iChar; + std::vector > ret; + std::vector::iterator iWire; + std::vector >:: iterator iChar; PyObject *WireList, *CharList; @@ -352,8 +351,7 @@ static PyObject * makeWireString(PyObject *self, PyObject *args) } if (PyString_Check(intext)) { -// handle c type string - PyObject *p = Base::PyAsUnicodeObject(PyString_AsString(intext)); //ascii/utf8 to PyUni + PyObject *p = Base::PyAsUnicodeObject(PyString_AsString(intext)); if (!p) { Base::Console().Message("** makeWireString can't convert PyString.\n"); return NULL; @@ -362,7 +360,6 @@ static PyObject * makeWireString(PyObject *self, PyObject *args) unichars = PyUnicode_AS_UNICODE(p); } else if (PyUnicode_Check(intext)) { -// handle ucs-2/4 input (Py_UNICODE object) pysize = PyUnicode_GetSize(intext); unichars = PyUnicode_AS_UNICODE(intext); } @@ -375,21 +372,20 @@ static PyObject * makeWireString(PyObject *self, PyObject *args) ret = FT2FC(unichars,pysize,dir,fontfile,height,track); // get vector of wire chars } catch (Standard_DomainError) { // Standard_DomainError is OCC error. - PyErr_SetString(PyExc_Exception, "makeWireString failed - OCC"); + PyErr_SetString(PyExc_Exception, "makeWireString failed - Standard_DomainError"); return NULL; - } + } catch (std::runtime_error& e) { // FT2 or FT2FC errors PyErr_SetString(PyExc_Exception, e.what()); return NULL; - } + } // if (ret not empty) CharList = PyList_New(0); for (iChar = ret.begin(); iChar !=ret.end(); ++iChar) { WireList = PyList_New(0); for (iWire = iChar->begin(); iWire != iChar->end(); ++iWire){ - PyObject* newobj = new TopoShapeWirePy(new TopoShape (*iWire)); - PyList_Append(WireList,newobj); + PyList_Append(WireList,*iWire); } // if (list not empty) PyList_Append(CharList,WireList); diff --git a/src/Mod/Part/App/FT2FC.cpp b/src/Mod/Part/App/FT2FC.cpp index 7ab73a76c8..7d1ae8d12e 100644 --- a/src/Mod/Part/App/FT2FC.cpp +++ b/src/Mod/Part/App/FT2FC.cpp @@ -1,11 +1,5 @@ //$$INSERT legal.txt -#include - -#include -#include FT_FREETYPE_H -#include FT_OUTLINE_H -#include FT_GLYPH_H -#include FT_TYPES_H +#include "PreCompiled.h" #include #include @@ -26,19 +20,27 @@ #include #include +#include "TopoShape.h" +#include "TopoShapePy.h" +#include "TopoShapeEdgePy.h" +#include "TopoShapeWirePy.h" + +#include +#include FT_FREETYPE_H +#include FT_OUTLINE_H +#include FT_GLYPH_H +#include FT_TYPES_H + #include "FT2FC.h" -typedef unsigned long UNICHAR; // should be = Py_UNICODE?? ul is FT2's codepoint type -typedef std::vector > FT2FCRET; +using namespace Part; -// Private function prototypes -void getFTChar(UNICHAR c); -std::vector getGlyphContours(); -FT_Vector getKerning(UNICHAR lc, UNICHAR rc); -TopoDS_Wire edgesToWire(std::vector Edges); +typedef unsigned long UNICHAR; // ul is FT2's codepoint type <=> Py_UNICODE2/4 +typedef std::vector > FT2FCRET; -struct FTDC_Ctx { // FT Decomp Context for 1 char - std::vector TWires; +// FT Decomp Context for 1 char +struct FTDC_Ctx { + std::vector TWires; std::vector Edges; UNICHAR currchar; int penpos; @@ -46,9 +48,15 @@ struct FTDC_Ctx { // FT Decomp Context for 1 char FT_Vector LastVert; }; -// Made a TopoDS_Wire from a list of TopoDS_Edges -TopoDS_Wire edgesToWire(std::vector Edges) { - TopoDS_Wire result; +// Private function prototypes +//void getFTChar(UNICHAR c); +std::vector getGlyphContours(); +FT_Vector getKerning(UNICHAR lc, UNICHAR rc); +TopoShapeWirePy* edgesToWire(std::vector Edges); + +// Make a TopoDS_Wire from a list of TopoDS_Edges +TopoShapeWirePy* edgesToWire(std::vector Edges) { + TopoDS_Wire occwire; std::vector::iterator iEdge; // if Edges.empty() ???? BRepBuilderAPI_MakeWire mkWire; @@ -56,8 +64,10 @@ TopoDS_Wire edgesToWire(std::vector Edges) { mkWire.Add(*iEdge); } // if(mkWire.Done()) ??? - result = mkWire.Wire(); - return(result); + occwire = mkWire.Wire(); + TopoShapeWirePy* newwire = new TopoShapeWirePy(new TopoShape (occwire)); + + return(newwire); } // FT Decompose callbacks and data defns @@ -65,13 +75,13 @@ TopoDS_Wire edgesToWire(std::vector Edges) { // p points to the context where we remember what happened previously (last point, etc) static int move_cb(const FT_Vector* pt, void* p) { FTDC_Ctx* dc = (FTDC_Ctx*) p; - if (!dc->Edges.empty()){ // empty on first contour. (or messed up font) - TopoDS_Wire newwire; + if (!dc->Edges.empty()){ + TopoShapeWirePy* newwire; newwire = edgesToWire(dc->Edges); dc->TWires.push_back(newwire); dc->Edges.clear(); } - dc->LastVert.x = pt->x + dc->penpos; // move along baseline + dc->LastVert.x = pt->x + dc->penpos; dc->LastVert.y = pt->y; return 0; } @@ -80,7 +90,7 @@ static int move_cb(const FT_Vector* pt, void* p) { static int line_cb(const FT_Vector* pt, void* p) { FTDC_Ctx* dc = (FTDC_Ctx*) p; // convert font coords to FC/OCC coords - float v1x = dc->scalefactor * dc->LastVert.x; // LastVert already moved along baseline + float v1x = dc->scalefactor * dc->LastVert.x; float v1y = dc->scalefactor * dc->LastVert.y; float v2x = dc->scalefactor * (pt->x + dc->penpos); float v2y = dc->scalefactor * pt->y; @@ -111,8 +121,8 @@ static int quad_cb(const FT_Vector* pt0, const FT_Vector* pt1, void* p) { Poles.SetValue(1, v1); Poles.SetValue(2, c1); Poles.SetValue(3, v2); - // "new" bcseg? need to free this, but don't know when! does makeedge need it forever? or just for creation? - // how to delete a "handle"? + // "new" bcseg? need to free this, but don't know when. does makeedge need it forever? or just for creation? + // how to delete a "handle"? memory leak? Handle(Geom_BezierCurve) bcseg = new Geom_BezierCurve(Poles); BRepBuilderAPI_MakeEdge makeEdge(bcseg, v1, v2); TopoDS_Edge edge = makeEdge.Edge(); @@ -154,29 +164,29 @@ static int cubic_cb(const FT_Vector* pt0, const FT_Vector* pt1, const FT_Vector* } // FT Callbacks structure -static FT_Outline_Funcs outline_funcs = { +static FT_Outline_Funcs FTcbFuncs = { (FT_Outline_MoveToFunc)move_cb, (FT_Outline_LineToFunc)line_cb, (FT_Outline_ConicToFunc)quad_cb, (FT_Outline_CubicToFunc)cubic_cb, - 0, 0 // not needed for FC + 0, 0 // not needed for FC }; -// load glyph outline into FTFont. +/*// load glyph outline into FTFont. void getFTChar(FT_Face FTFont, UNICHAR c) { FT_Error error; - FT_UInt flags = FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP; + FT_UInt FTLoadFlags = FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP; std::stringstream ErrorMsg; error = FT_Load_Char(FTFont, c, - flags); + FTLoadFlags); if(error) { ErrorMsg << "FT_Load_Char failed: " << error; throw std::runtime_error(ErrorMsg.str()); } return; - } + }*/ // get kerning values for this char pair //TODO: should check FT_HASKERNING flag? @@ -197,62 +207,56 @@ FT_Vector getKerning(FT_Face FTFont, UNICHAR lc, UNICHAR rc) { return(retXY); } -// get glyph outline for current char -std::vector getGlyphContours(FT_Face FTFont, UNICHAR currchar, int PenPos, float Scale) { +// get glyph outline in wires +std::vector getGlyphContours(FT_Face FTFont, UNICHAR currchar, int PenPos, float Scale) { FT_Error error = 0; std::stringstream ErrorMsg; - FT_Outline* FTOPointer; +// FT_Outline* pFTO = &FTFont->glyph->outline; FTDC_Ctx ctx; - FTOPointer = &FTFont->glyph->outline; -// ctx.ConCnt = 0; -// ctx.SegCnt = 0; ctx.currchar = currchar; ctx.penpos = PenPos; ctx.scalefactor = Scale; - ctx.Edges.clear(); - ctx.TWires.clear(); +// ctx.Edges.clear(); +// ctx.TWires.clear(); - error = FT_Outline_Decompose(FTOPointer, &outline_funcs, &ctx); + error = FT_Outline_Decompose(&FTFont->glyph->outline, + &FTcbFuncs, + &ctx); if(error) { ErrorMsg << "FT_Decompose failed: " << error; throw std::runtime_error(ErrorMsg.str()); } - if (!ctx.Edges.empty()){ // make the last twire - TopoDS_Wire newwire; - newwire = edgesToWire(ctx.Edges); - ctx.TWires.push_back(newwire); +// make the last twire + if (!ctx.Edges.empty()){ + ctx.TWires.push_back(edgesToWire(ctx.Edges)); } + return(ctx.TWires); - } +} // get string's wires (contours) in FC/OCC coords FT2FCRET FT2FC(const Py_UNICODE *pustring, const size_t length, const char *FontPath, const char *FontName, - const float stringheight, // in fc coords - const int tracking) { // in fc coords -/*FT2FCRET _FT2FC(const std::vector stringvec, - const char * FontPath, - const char * FontName, - const float stringheight, // in fc coords - const int tracking) { // in fc coords*/ + const float stringheight, // fc coords + const int tracking) { // fc coords FT_Library FTLib; FT_Face FTFont; FT_Error error; - FT_Long FaceIndex; + FT_Long FaceIndex = 0; // some fonts have multiple faces FT_Vector kern; + FT_UInt FTLoadFlags = FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP; + std::string FontSpec; std::stringstream ErrorMsg; - float scalefactor; - UNICHAR prevchar,currchar; - int cadv,PenPos; -// size_t i, length; + UNICHAR prevchar = 0, currchar = 0; + int cadv,PenPos = 0; size_t i; - std::vector CharWires; + std::vector CharWires; FT2FCRET Ret; error = FT_Init_FreeType(&FTLib); @@ -264,10 +268,8 @@ FT2FCRET FT2FC(const Py_UNICODE *pustring, std::string tmpPath = FontPath; // can't concat const char* std::string tmpName = FontName; FontSpec = tmpPath + tmpName; - - FaceIndex = 0; // some fonts have multiple faces - // NOTE: FT does not return an error if font file not found. + // FT does not return an error if font file not found? std::ifstream is; is.open (FontSpec.c_str()); if (!is) { @@ -296,15 +298,18 @@ FT2FCRET FT2FC(const Py_UNICODE *pustring, throw std::runtime_error(ErrorMsg.str()); } - prevchar = 0; - PenPos = 0; scalefactor = float(stringheight/FTFont->height); -// length = stringvec.size(); -// for (i=0;iglyph->advance.x; kern = getKerning(FTFont,prevchar,currchar); PenPos += kern.x; @@ -316,7 +321,7 @@ FT2FCRET FT2FC(const Py_UNICODE *pustring, // not entirely happy with tracking solution. It's specified in FC units, // so we have to convert back to font units to use it here. We could // lose some accuracy. Hard to put it into FT callbacks since tracking - // only affects position of chars 2 - n. + // only affects position of chars 2 - n. Don't want to loop 2x through wires. PenPos += cadv + int(tracking/scalefactor); prevchar = currchar; } @@ -330,17 +335,3 @@ FT2FCRET FT2FC(const Py_UNICODE *pustring, return(Ret); } -/*FT2FCRET FT2FCpu(const Py_UNICODE *pustring, - const size_t length, - const char *FontPath, - const char *FontName, - const float stringheight, // in fc coords - const int tracking) { // in fc coords - size_t i; - std::vector stringvec(length, 0); - for (i=0;i > FT2FC(const Py_UNICODE *unichars, +std::vector > FT2FC(const Py_UNICODE *unichars, const size_t length, const char *FontPath, const char *FontName, From 830743d2e621ee840e9aed7b78e6a4154207af86 Mon Sep 17 00:00:00 2001 From: WandererFan Date: Fri, 22 Mar 2013 09:38:32 -0400 Subject: [PATCH 8/9] Refactor PyList logic to FT2FC from AppPartPy. --- src/Mod/Part/App/AppPartPy.cpp | 15 +- src/Mod/Part/App/FT2FC.cpp | 327 ++++++++++++++++----------------- src/Mod/Part/App/FT2FC.h | 13 +- 3 files changed, 178 insertions(+), 177 deletions(-) diff --git a/src/Mod/Part/App/AppPartPy.cpp b/src/Mod/Part/App/AppPartPy.cpp index 27b47c0a06..3f387fcbfa 100644 --- a/src/Mod/Part/App/AppPartPy.cpp +++ b/src/Mod/Part/App/AppPartPy.cpp @@ -335,11 +335,12 @@ static PyObject * makeWireString(PyObject *self, PyObject *args) Py_UNICODE *unichars; Py_ssize_t pysize; - std::vector > ret; - std::vector::iterator iWire; - std::vector >:: iterator iChar; +// std::vector > ret; +// std::vector::iterator iWire; +// std::vector >:: iterator iChar; - PyObject *WireList, *CharList; +// PyObject *WireList, *CharList; + PyObject *CharList; if (!PyArg_ParseTuple(args, "Ossf|i", &intext, &dir, @@ -369,7 +370,7 @@ static PyObject * makeWireString(PyObject *self, PyObject *args) } try { - ret = FT2FC(unichars,pysize,dir,fontfile,height,track); // get vector of wire chars + CharList = FT2FC(unichars,pysize,dir,fontfile,height,track); // get list of wire chars } catch (Standard_DomainError) { // Standard_DomainError is OCC error. PyErr_SetString(PyExc_Exception, "makeWireString failed - Standard_DomainError"); @@ -380,7 +381,7 @@ static PyObject * makeWireString(PyObject *self, PyObject *args) return NULL; } - // if (ret not empty) +/* // if (ret not empty) CharList = PyList_New(0); for (iChar = ret.begin(); iChar !=ret.end(); ++iChar) { WireList = PyList_New(0); @@ -389,7 +390,7 @@ static PyObject * makeWireString(PyObject *self, PyObject *args) } // if (list not empty) PyList_Append(CharList,WireList); - } + }*/ return (CharList); } diff --git a/src/Mod/Part/App/FT2FC.cpp b/src/Mod/Part/App/FT2FC.cpp index 7d1ae8d12e..3fb22ee72a 100644 --- a/src/Mod/Part/App/FT2FC.cpp +++ b/src/Mod/Part/App/FT2FC.cpp @@ -36,11 +36,125 @@ using namespace Part; typedef unsigned long UNICHAR; // ul is FT2's codepoint type <=> Py_UNICODE2/4 -typedef std::vector > FT2FCRET; +//typedef std::vector > FT2FCRET; +typedef PyObject* FT2FCRET; +// Private function prototypes +//std::vector getGlyphContours(); +PyObject* getGlyphContours(FT_Face FTFont, UNICHAR currchar, int PenPos, float Scale); +FT_Vector getKerning(FT_Face FTFont, UNICHAR lc, UNICHAR rc); +TopoShapeWirePy* edgesToWire(std::vector Edges); + +// get string's wires (contours) in FC/OCC coords +//FT2FCRET FT2FC(const Py_UNICODE *pustring, +PyObject* FT2FC(const Py_UNICODE *pustring, + const size_t length, + const char *FontPath, + const char *FontName, + const float stringheight, // fc coords + const int tracking) { // fc coords + FT_Library FTLib; + FT_Face FTFont; + FT_Error error; + FT_Long FaceIndex = 0; // some fonts have multiple faces + FT_Vector kern; + FT_UInt FTLoadFlags = FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP; + + std::string FontSpec; + std::stringstream ErrorMsg; + float scalefactor; + UNICHAR prevchar = 0, currchar = 0; + int cadv,PenPos = 0, PyErr; + size_t i; +// std::vector CharWires; +// FT2FCRET Ret; + + PyObject *WireList, *CharList; + + error = FT_Init_FreeType(&FTLib); + if(error) { + ErrorMsg << "FT_Init_FreeType failed: " << error; + throw std::runtime_error(ErrorMsg.str()); + } + + std::string tmpPath = FontPath; // can't concat const char* + std::string tmpName = FontName; + FontSpec = tmpPath + tmpName; + + // FT does not return an error if font file not found? + std::ifstream is; + is.open (FontSpec.c_str()); + if (!is) { + ErrorMsg << "Font file not found: " << FontSpec; + throw std::runtime_error(ErrorMsg.str()); + } + // maybe boost::filesystem::exists for x-platform?? + + error = FT_New_Face(FTLib,FontSpec.c_str(),FaceIndex, &FTFont); + if(error) { + ErrorMsg << "FT_New_Face failed: " << error; + throw std::runtime_error(ErrorMsg.str()); + } + +//TODO: check that FTFont is scalable? only relevant for hinting etc? + +// FT2 blows up if char size is not set to some non-zero value. +// This sets size to 48 point. Magic. + error = FT_Set_Char_Size(FTFont, + 0, /* char_width in 1/64th of points */ + 48*64, /* char_height in 1/64th of points */ + 0, /* horizontal device resolution */ + 0 ); /* vertical device resolution */ + if(error) { + ErrorMsg << "FT_Set_Char_Size failed: " << error; + throw std::runtime_error(ErrorMsg.str()); + } + + scalefactor = float(stringheight/FTFont->height); + CharList = PyList_New(0); + for (i=0; iglyph->advance.x; + kern = getKerning(FTFont,prevchar,currchar); + PenPos += kern.x; +// CharWires = getGlyphContours(FTFont,currchar,PenPos, scalefactor); + WireList = getGlyphContours(FTFont,currchar,PenPos, scalefactor); +// if (CharWires.empty()) // whitespace char + if (!PyList_Size(WireList)) // empty ==> whitespace + std::cout << "char " << i << " = " << hex << std::showbase << currchar << " has no wires! " << std::endl; + else +// Ret.push_back(CharWires); + PyErr = PyList_Append(CharList, WireList); //add error check + // not entirely happy with tracking solution. It's specified in FC units, + // so we have to convert back to font units to use it here. We could + // lose some accuracy. Hard to put it into FT callbacks since tracking + // only affects position of chars 2 - n. Don't want to loop 2x through wires. + PenPos += cadv + int(tracking/scalefactor); + prevchar = currchar; + } + + error = FT_Done_FreeType(FTLib); + if(error) { + ErrorMsg << "FT_Done_FreeType failed: " << error; + throw std::runtime_error(ErrorMsg.str()); + } + + return(CharList); + } + +//********** FT Decompose callbacks and data defns // FT Decomp Context for 1 char struct FTDC_Ctx { - std::vector TWires; +// std::vector TWires; + PyObject* WireList; std::vector Edges; UNICHAR currchar; int penpos; @@ -48,37 +162,16 @@ struct FTDC_Ctx { FT_Vector LastVert; }; -// Private function prototypes -//void getFTChar(UNICHAR c); -std::vector getGlyphContours(); -FT_Vector getKerning(UNICHAR lc, UNICHAR rc); -TopoShapeWirePy* edgesToWire(std::vector Edges); - -// Make a TopoDS_Wire from a list of TopoDS_Edges -TopoShapeWirePy* edgesToWire(std::vector Edges) { - TopoDS_Wire occwire; - std::vector::iterator iEdge; - // if Edges.empty() ???? - BRepBuilderAPI_MakeWire mkWire; - for (iEdge = Edges.begin(); iEdge != Edges.end(); ++iEdge){ - mkWire.Add(*iEdge); - } - // if(mkWire.Done()) ??? - occwire = mkWire.Wire(); - TopoShapeWirePy* newwire = new TopoShapeWirePy(new TopoShape (occwire)); - - return(newwire); - } - -// FT Decompose callbacks and data defns // move_cb called for start of new contour. pt is xy of contour start. // p points to the context where we remember what happened previously (last point, etc) static int move_cb(const FT_Vector* pt, void* p) { FTDC_Ctx* dc = (FTDC_Ctx*) p; + int PyErr; if (!dc->Edges.empty()){ TopoShapeWirePy* newwire; newwire = edgesToWire(dc->Edges); - dc->TWires.push_back(newwire); +// dc->TWires.push_back(newwire); + PyErr = PyList_Append(dc->WireList, newwire); // add error check dc->Edges.clear(); } dc->LastVert.x = pt->x + dc->penpos; @@ -172,21 +265,39 @@ static FT_Outline_Funcs FTcbFuncs = { 0, 0 // not needed for FC }; -/*// load glyph outline into FTFont. -void getFTChar(FT_Face FTFont, UNICHAR c) { - FT_Error error; - FT_UInt FTLoadFlags = FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP; - std::stringstream ErrorMsg; +// + +//********** FT2FC Helpers +// get glyph outline in wires +//std::vector getGlyphContours(FT_Face FTFont, UNICHAR currchar, int PenPos, float Scale) { +PyObject* getGlyphContours(FT_Face FTFont, UNICHAR currchar, int PenPos, float Scale) { + FT_Error error = 0; + std::stringstream ErrorMsg; + FTDC_Ctx ctx; + int PyErr; - error = FT_Load_Char(FTFont, - c, - FTLoadFlags); + ctx.currchar = currchar; + ctx.penpos = PenPos; + ctx.scalefactor = Scale; + ctx.WireList = PyList_New(0); + + error = FT_Outline_Decompose(&FTFont->glyph->outline, + &FTcbFuncs, + &ctx); if(error) { - ErrorMsg << "FT_Load_Char failed: " << error; + ErrorMsg << "FT_Decompose failed: " << error; throw std::runtime_error(ErrorMsg.str()); - } - return; - }*/ + } + +// make the last twire + if (!ctx.Edges.empty()){ +// ctx.TWires.push_back(edgesToWire(ctx.Edges)); + PyErr = PyList_Append(ctx.WireList, edgesToWire(ctx.Edges)); // add error check + } + +// return(ctx.TWires); + return(ctx.WireList); +} // get kerning values for this char pair //TODO: should check FT_HASKERNING flag? @@ -207,131 +318,19 @@ FT_Vector getKerning(FT_Face FTFont, UNICHAR lc, UNICHAR rc) { return(retXY); } -// get glyph outline in wires -std::vector getGlyphContours(FT_Face FTFont, UNICHAR currchar, int PenPos, float Scale) { - FT_Error error = 0; - std::stringstream ErrorMsg; -// FT_Outline* pFTO = &FTFont->glyph->outline; - FTDC_Ctx ctx; +// Make a TopoDS_Wire from a list of TopoDS_Edges +TopoShapeWirePy* edgesToWire(std::vector Edges) { + TopoDS_Wire occwire; + std::vector::iterator iEdge; + // if Edges.empty() ???? + BRepBuilderAPI_MakeWire mkWire; + for (iEdge = Edges.begin(); iEdge != Edges.end(); ++iEdge){ + mkWire.Add(*iEdge); + } + // if(mkWire.Done()) ??? + occwire = mkWire.Wire(); + TopoShapeWirePy* newwire = new TopoShapeWirePy(new TopoShape (occwire)); - ctx.currchar = currchar; - ctx.penpos = PenPos; - ctx.scalefactor = Scale; -// ctx.Edges.clear(); -// ctx.TWires.clear(); - - error = FT_Outline_Decompose(&FTFont->glyph->outline, - &FTcbFuncs, - &ctx); - if(error) { - ErrorMsg << "FT_Decompose failed: " << error; - throw std::runtime_error(ErrorMsg.str()); - } - -// make the last twire - if (!ctx.Edges.empty()){ - ctx.TWires.push_back(edgesToWire(ctx.Edges)); - } - - return(ctx.TWires); -} - -// get string's wires (contours) in FC/OCC coords -FT2FCRET FT2FC(const Py_UNICODE *pustring, - const size_t length, - const char *FontPath, - const char *FontName, - const float stringheight, // fc coords - const int tracking) { // fc coords - FT_Library FTLib; - FT_Face FTFont; - FT_Error error; - FT_Long FaceIndex = 0; // some fonts have multiple faces - FT_Vector kern; - FT_UInt FTLoadFlags = FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP; - - std::string FontSpec; - std::stringstream ErrorMsg; - float scalefactor; - UNICHAR prevchar = 0, currchar = 0; - int cadv,PenPos = 0; - size_t i; - std::vector CharWires; - FT2FCRET Ret; - - error = FT_Init_FreeType(&FTLib); - if(error) { - ErrorMsg << "FT_Init_FreeType failed: " << error; - throw std::runtime_error(ErrorMsg.str()); - } - - std::string tmpPath = FontPath; // can't concat const char* - std::string tmpName = FontName; - FontSpec = tmpPath + tmpName; - - // FT does not return an error if font file not found? - std::ifstream is; - is.open (FontSpec.c_str()); - if (!is) { - ErrorMsg << "Font file not found: " << FontSpec; - throw std::runtime_error(ErrorMsg.str()); - } - // maybe boost::filesystem::exists for x-platform?? - - error = FT_New_Face(FTLib,FontSpec.c_str(),FaceIndex, &FTFont); - if(error) { - ErrorMsg << "FT_New_Face failed: " << error; - throw std::runtime_error(ErrorMsg.str()); - } - -//TODO: check that FTFont is scalable? only relevant for hinting etc? - -// FT2 blows up if char size is not set to some non-zero value. -// This sets size to 48 point. Magic. - error = FT_Set_Char_Size(FTFont, - 0, /* char_width in 1/64th of points */ - 48*64, /* char_height in 1/64th of points */ - 0, /* horizontal device resolution */ - 0 ); /* vertical device resolution */ - if(error) { - ErrorMsg << "FT_Set_Char_Size failed: " << error; - throw std::runtime_error(ErrorMsg.str()); - } - - scalefactor = float(stringheight/FTFont->height); - for (i=0; iglyph->advance.x; - kern = getKerning(FTFont,prevchar,currchar); - PenPos += kern.x; - CharWires = getGlyphContours(FTFont,currchar,PenPos, scalefactor); - if (CharWires.empty()) // whitespace char - std::cout << "char " << i << " = " << hex << std::showbase << currchar << " has no wires! " << std::endl; - else - Ret.push_back(CharWires); - // not entirely happy with tracking solution. It's specified in FC units, - // so we have to convert back to font units to use it here. We could - // lose some accuracy. Hard to put it into FT callbacks since tracking - // only affects position of chars 2 - n. Don't want to loop 2x through wires. - PenPos += cadv + int(tracking/scalefactor); - prevchar = currchar; - } - - error = FT_Done_FreeType(FTLib); - if(error) { - ErrorMsg << "FT_Done_FreeType failed: " << error; - throw std::runtime_error(ErrorMsg.str()); - } - - return(Ret); - } + return(newwire); + } diff --git a/src/Mod/Part/App/FT2FC.h b/src/Mod/Part/App/FT2FC.h index 7d8bfca535..2d2eadac0f 100644 --- a/src/Mod/Part/App/FT2FC.h +++ b/src/Mod/Part/App/FT2FC.h @@ -2,11 +2,12 @@ #ifndef FT2FC_H #define FT2FC_H // public function -std::vector > FT2FC(const Py_UNICODE *unichars, - const size_t length, - const char *FontPath, - const char *FontName, - const float stringheight, - const int tracking); +//std::vector > FT2FC(const Py_UNICODE *unichars, +PyObject* FT2FC(const Py_UNICODE *unichars, + const size_t length, + const char *FontPath, + const char *FontName, + const float stringheight, + const int tracking); #endif // FT2FC_H From c723cc99d1451793cf0dd396993bfc477681d69c Mon Sep 17 00:00:00 2001 From: WandererFan Date: Fri, 22 Mar 2013 10:35:34 -0400 Subject: [PATCH 9/9] Tidy PyList creation code. Add test driver. --- src/Mod/Part/App/AppPartPy.cpp | 25 +------------- src/Mod/Part/App/FT2FC.cpp | 21 +++--------- src/Mod/Part/App/FT2FC.h | 1 - src/Mod/Test/testmakeWireString.py | 52 ++++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 41 deletions(-) create mode 100644 src/Mod/Test/testmakeWireString.py diff --git a/src/Mod/Part/App/AppPartPy.cpp b/src/Mod/Part/App/AppPartPy.cpp index 3f387fcbfa..6d103281ac 100644 --- a/src/Mod/Part/App/AppPartPy.cpp +++ b/src/Mod/Part/App/AppPartPy.cpp @@ -118,14 +118,6 @@ #include "ImportStep.h" #include "edgecluster.h" -/*//needed in AppPartPy??? -#include -#include FT_FREETYPE_H -#include FT_OUTLINE_H -#include FT_GLYPH_H -#include FT_TYPES_H -//??*/ - #include "FT2FC.h" using Base::Console; @@ -335,11 +327,6 @@ static PyObject * makeWireString(PyObject *self, PyObject *args) Py_UNICODE *unichars; Py_ssize_t pysize; -// std::vector > ret; -// std::vector::iterator iWire; -// std::vector >:: iterator iChar; - -// PyObject *WireList, *CharList; PyObject *CharList; if (!PyArg_ParseTuple(args, "Ossf|i", &intext, @@ -381,16 +368,6 @@ static PyObject * makeWireString(PyObject *self, PyObject *args) return NULL; } -/* // if (ret not empty) - CharList = PyList_New(0); - for (iChar = ret.begin(); iChar !=ret.end(); ++iChar) { - WireList = PyList_New(0); - for (iWire = iChar->begin(); iWire != iChar->end(); ++iWire){ - PyList_Append(WireList,*iWire); - } - // if (list not empty) - PyList_Append(CharList,WireList); - }*/ return (CharList); } @@ -1599,7 +1576,7 @@ struct PyMethodDef Part_methods[] = { "makeLoft(list of wires) -- Create a loft shape."}, {"makeWireString" ,makeWireString ,METH_VARARGS, - "makeWireString(fontdir,fontfile,string,height,[track]) -- Make wires in the form of a string."}, + "makeWireString(fontdir,fontfile,string,height,[track]) -- Make list of wires in the form of a string's characters."}, {"cast_to_shape" ,cast_to_shape,METH_VARARGS, "cast_to_shape(shape) -- Cast to the actual shape type"}, diff --git a/src/Mod/Part/App/FT2FC.cpp b/src/Mod/Part/App/FT2FC.cpp index 3fb22ee72a..014ac98a0f 100644 --- a/src/Mod/Part/App/FT2FC.cpp +++ b/src/Mod/Part/App/FT2FC.cpp @@ -36,18 +36,14 @@ using namespace Part; typedef unsigned long UNICHAR; // ul is FT2's codepoint type <=> Py_UNICODE2/4 -//typedef std::vector > FT2FCRET; -typedef PyObject* FT2FCRET; // Private function prototypes -//std::vector getGlyphContours(); PyObject* getGlyphContours(FT_Face FTFont, UNICHAR currchar, int PenPos, float Scale); FT_Vector getKerning(FT_Face FTFont, UNICHAR lc, UNICHAR rc); TopoShapeWirePy* edgesToWire(std::vector Edges); // get string's wires (contours) in FC/OCC coords -//FT2FCRET FT2FC(const Py_UNICODE *pustring, -PyObject* FT2FC(const Py_UNICODE *pustring, +PyObject* FT2FC(const Py_UNICODE *PyUString, const size_t length, const char *FontPath, const char *FontName, @@ -64,10 +60,8 @@ PyObject* FT2FC(const Py_UNICODE *pustring, std::stringstream ErrorMsg; float scalefactor; UNICHAR prevchar = 0, currchar = 0; - int cadv,PenPos = 0, PyErr; + int cadv, PenPos = 0, PyErr; size_t i; -// std::vector CharWires; -// FT2FCRET Ret; PyObject *WireList, *CharList; @@ -113,7 +107,7 @@ PyObject* FT2FC(const Py_UNICODE *pustring, scalefactor = float(stringheight/FTFont->height); CharList = PyList_New(0); for (i=0; iglyph->advance.x; kern = getKerning(FTFont,prevchar,currchar); PenPos += kern.x; -// CharWires = getGlyphContours(FTFont,currchar,PenPos, scalefactor); WireList = getGlyphContours(FTFont,currchar,PenPos, scalefactor); -// if (CharWires.empty()) // whitespace char if (!PyList_Size(WireList)) // empty ==> whitespace std::cout << "char " << i << " = " << hex << std::showbase << currchar << " has no wires! " << std::endl; else -// Ret.push_back(CharWires); PyErr = PyList_Append(CharList, WireList); //add error check // not entirely happy with tracking solution. It's specified in FC units, // so we have to convert back to font units to use it here. We could @@ -170,7 +161,6 @@ static int move_cb(const FT_Vector* pt, void* p) { if (!dc->Edges.empty()){ TopoShapeWirePy* newwire; newwire = edgesToWire(dc->Edges); -// dc->TWires.push_back(newwire); PyErr = PyList_Append(dc->WireList, newwire); // add error check dc->Edges.clear(); } @@ -196,6 +186,7 @@ static int line_cb(const FT_Vector* pt, void* p) { dc->LastVert.y = pt->y; return 0; } + // quad_cb called for quadratic (conic) BCurve segment in the current contour // (ie V-C-V in TTF fonts). BCurve(LastVert -- pt0 -- pt1) static int quad_cb(const FT_Vector* pt0, const FT_Vector* pt1, void* p) { @@ -214,7 +205,7 @@ static int quad_cb(const FT_Vector* pt0, const FT_Vector* pt1, void* p) { Poles.SetValue(1, v1); Poles.SetValue(2, c1); Poles.SetValue(3, v2); - // "new" bcseg? need to free this, but don't know when. does makeedge need it forever? or just for creation? + // "new" bcseg? need to free this? don't know when. does makeedge need it forever? or just for creation? // how to delete a "handle"? memory leak? Handle(Geom_BezierCurve) bcseg = new Geom_BezierCurve(Poles); BRepBuilderAPI_MakeEdge makeEdge(bcseg, v1, v2); @@ -265,8 +256,6 @@ static FT_Outline_Funcs FTcbFuncs = { 0, 0 // not needed for FC }; -// - //********** FT2FC Helpers // get glyph outline in wires //std::vector getGlyphContours(FT_Face FTFont, UNICHAR currchar, int PenPos, float Scale) { diff --git a/src/Mod/Part/App/FT2FC.h b/src/Mod/Part/App/FT2FC.h index 2d2eadac0f..cff39e9c0c 100644 --- a/src/Mod/Part/App/FT2FC.h +++ b/src/Mod/Part/App/FT2FC.h @@ -2,7 +2,6 @@ #ifndef FT2FC_H #define FT2FC_H // public function -//std::vector > FT2FC(const Py_UNICODE *unichars, PyObject* FT2FC(const Py_UNICODE *unichars, const size_t length, const char *FontPath, diff --git a/src/Mod/Test/testmakeWireString.py b/src/Mod/Test/testmakeWireString.py new file mode 100644 index 0000000000..a75a58357c --- /dev/null +++ b/src/Mod/Test/testmakeWireString.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# tester for Part.makeWireString + +import FreeCAD +import Part +import PartDesign + +print "testWire started" + +# test strings +# if string contains funky characters, it has to be declared as Unicode or it +# turns into the default encoding (usually utf8). FT2 doesn't do utf8. +#String = 'Wide WMA_' # wide glyphs for tracking +#String = 'Big' +#String = u'ecAnO' # UCS-2 w/ only ASCII +#String = u'ucs2uéçÄñØ' # UCS-2 +#String = 'utf8!uéçÄñØ' # UTF-8 +#String = 'abcdefghijklmnopqrstuvwxyz0123456789' +#String = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +#String = 'Big Daddy' # white space +#String = 'AVWAIXA.V' # kerning +String = 'FreeCAD' # ASCII + +#FontPath = '/usr/share/fonts/truetype/msttcorefonts/' +#FontName = 'Times_New_Roman_Italic.ttf' +FontPath = '/usr/share/fonts/truetype/msttcorefonts/' +#FontName = 'Arial.ttf' +FontName = 'NOTArial.ttf' # font file not found error +#FontPath = '/usr/share/fonts/truetype/msttcorefonts/' +#FontName = 'ariali.ttf' #symlink to ttf +#FontPath = '/usr/share/fonts/truetype/' +#FontName = 'Peterbuilt.ttf' # overlapping script font +#FontPath = '/usr/share/fonts/truetype/' +#FontName = 'dyspepsia.ttf' # overlapping script font # :) + +Height = 2000 # out string height FCunits +Track = 0 # intercharacter spacing + +print "testWire.py input String contains ", len(String), " characters." + +s = Part.makeWireString(String,FontPath,FontName,Height,Track) + +print "returned from makeWireString" +print "testWire.py output contains ", len(s), " WireChars." + +for char in s: + for contour in char: + Part.show(contour) + +print "testWire ended."