diff --git a/CMakeLists.txt b/CMakeLists.txt index 6d87248519..307fe0c8e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -106,8 +106,10 @@ OPTION(FREECAD_USE_EXTERNAL_ZIPIOS "Use system installed zipios++ instead of the OPTION(FREECAD_USE_EXTERNAL_PIVY "Use system installed python-pivy instead of the bundled." OFF) if(MSVC) OPTION(FREECAD_USE_3DCONNEXION "Use the 3D connexion SDK to support 3d mouse." ON) +OPTION(FREECAD_USE_FREETYPE "Builds the features using FreeType libs" OFF) else(MSVC) set(FREECAD_USE_3DCONNEXION OFF) +OPTION(FREECAD_USE_FREETYPE "Builds the features using FreeType libs" ON) endif(MSVC) # if this is set override some options @@ -323,6 +325,12 @@ MARK_AS_ADVANCED(FORCE FREECAD_LIBPACK_CHECKFILE6X FREECAD_LIBPACK_CHECKFILE7X) endforeach(it) endmacro(fc_wrap_cpp) +#--------------------FreeType----------------------- + if(FREECAD_USE_FREETYPE) + find_package(FreeType) + endif(FREECAD_USE_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..83a9cc6b42 100644 --- a/src/Mod/Part/App/AppPartPy.cpp +++ b/src/Mod/Part/App/AppPartPy.cpp @@ -118,6 +118,10 @@ #include "ImportStep.h" #include "edgecluster.h" +#ifdef FCUseFreeType +# include "FT2FC.h" +#endif + using Base::Console; using namespace Part; using namespace std; @@ -313,6 +317,73 @@ show(PyObject *self, PyObject *args) Py_Return; } + +#ifdef FCUseFreeType + +static PyObject * makeWireString(PyObject *self, PyObject *args) +{ + PyObject *intext; + const char* dir; + const char* fontfile; + float height; + int track = 0; + + const char* text; + Py_UNICODE *unichars; + Py_ssize_t pysize; + + PyObject *CharList; + + if (!PyArg_ParseTuple(args, "Ossf|i", &intext, + &dir, + &fontfile, + &height, + &track)) { + Base::Console().Message("** makeWireString bad args.\n"); + return NULL; + } + + if (PyString_Check(intext)) { + PyObject *p = Base::PyAsUnicodeObject(PyString_AsString(intext)); + if (!p) { + Base::Console().Message("** makeWireString can't convert PyString.\n"); + return NULL; + } + pysize = PyUnicode_GetSize(p); + unichars = PyUnicode_AS_UNICODE(p); + } + else if (PyUnicode_Check(intext)) { + pysize = PyUnicode_GetSize(intext); + unichars = PyUnicode_AS_UNICODE(intext); + } + else { + Base::Console().Message("** makeWireString bad text parameter.\n"); + return NULL; + } + + try { + 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"); + return NULL; + } + catch (std::runtime_error& e) { // FT2 or FT2FC errors + PyErr_SetString(PyExc_Exception, e.what()); + return NULL; + } + + return (CharList); +} +#else + +static PyObject * makeWireString(PyObject *self, PyObject *args) +{ + PyErr_SetString(PyExc_Exception, "FreeCAD compiled without FreeType support! This method is disabled..."); + return NULL; +} + +#endif //#ifdef FCUseFreeType static PyObject * makeCompound(PyObject *self, PyObject *args) { @@ -1516,6 +1587,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 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/CMakeLists.txt b/src/Mod/Part/App/CMakeLists.txt index 9a62fb6fa6..afd21aba2f 100644 --- a/src/Mod/Part/App/CMakeLists.txt +++ b/src/Mod/Part/App/CMakeLists.txt @@ -4,6 +4,9 @@ else(MSVC) add_definitions(-DHAVE_LIMITS_H -DHAVE_CONFIG_H) endif(MSVC) +if(FREECAD_USE_FREETYPE) + add_definitions(-DFCUseFreeType) +endif(FREECAD_USE_FREETYPE) include_directories( ${CMAKE_BINARY_DIR}/src @@ -14,12 +17,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 ) @@ -234,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..4eefd3be96 --- /dev/null +++ b/src/Mod/Part/App/FT2FC.cpp @@ -0,0 +1,331 @@ +//$$INSERT legal.txt + +#ifdef FCUseFreeType + + +#include "PreCompiled.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#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" + +using namespace Part; + +typedef unsigned long UNICHAR; // ul is FT2's codepoint type <=> Py_UNICODE2/4 + +// Private function prototypes +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 +PyObject* FT2FC(const Py_UNICODE *PyUString, + 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; + + 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; + WireList = getGlyphContours(FTFont,currchar,PenPos, scalefactor); + if (!PyList_Size(WireList)) // empty ==> whitespace + std::cout << "char " << i << " = " << hex << std::showbase << currchar << " has no wires! " << std::endl; + else + 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; + PyObject* WireList; + std::vector Edges; + UNICHAR currchar; + int penpos; + float scalefactor; + FT_Vector LastVert; + }; + +// 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); + PyErr = PyList_Append(dc->WireList, newwire); // add error check + dc->Edges.clear(); + } + dc->LastVert.x = pt->x + dc->penpos; + 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; + 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->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? 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(); + dc->Edges.push_back(edge); + 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->LastVert.x = pt2->x + dc->penpos; + dc->LastVert.y = pt2->y; + return 0; + } + +// FT Callbacks structure +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 + }; + +//********** 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; + + 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_Decompose failed: " << error; + throw std::runtime_error(ErrorMsg.str()); + } + +// 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? +FT_Vector getKerning(FT_Face FTFont, UNICHAR lc, UNICHAR 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); + } + +// 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); + } + + +#endif //#ifdef FCUseFreeType \ No newline at end of file diff --git a/src/Mod/Part/App/FT2FC.h b/src/Mod/Part/App/FT2FC.h new file mode 100644 index 0000000000..cff39e9c0c --- /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 +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 + 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."