青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

eryar

PipeCAD - Plant Piping Design Software.
RvmTranslator - Translate AVEVA RVM to OBJ, glTF, etc.
posts - 603, comments - 590, trackbacks - 0, articles - 0

FreeType in OpenCASCADE

Posted on 2017-10-22 21:18 eryar 閱讀(2359) 評論(0)  編輯 收藏 引用 所屬分類: 2.OpenCASCADE

FreeType in OpenCASCADE

eryar@163.com

Abstract. FreeType is required for text display in the 3D viewer. FreeType is a software font engine that is designed to be small, efficient, highly customizable, and portable while capable of producing high-quality output(glyph images). It can be used in graphics libraries, display servers, font conversion tools, text image generation tools, and many other products as well. The blog is focus on the FreeType usage in OpenCASCADE to convert text to BRep shape.

Key Words. FreeType, OpenCASCADE, Text, BRep

1.Introduction

FreeType 2被設計為一種占用空間小的、高效的、高度可定制的、并且可以產生可移植的高品質輸出(符號圖像)。可以被用在諸如圖像庫、展出服務器、字體轉換工具、圖像文字產生工具等多種其它產品上。

注意FreeType 2是一種字體服務而沒有提供為實現文字布局或圖形化處理這樣高階的功能使用的API(比如帶色文字渲染之類的)。然而,它提供一個簡單的、易用的并且統一的接口實現對多種字體文件的訪問,從而大大簡化了這些高級的任務。

FreeType 2的發行遵循兩個開源許可:我們自己的BSD樣式的FreeType License和GPL(通用公共許可證)。它可以被用在任何程序中,無論是專有與否。

在常見的圖形庫中,如OpenSceneGraph, OpenCASCADE, HOOPS, Qt,等涉及到文字處理的,都會用到FreeType. 在一些游戲開發中,也會用到FreeType.本文主要對FreeType的用法作簡單介紹,這樣對FreeType有個直觀認識。然后再介紹FreeType對文字輪廓的表示方法,及如何生成三維文字。

在OpenCASCADE中文字可以二維的方式顯示,也可以三維的方式顯示,三維方式可以有線框和渲染模式,如下圖所示:

wps_clip_image-5702

Figure 1. 2D Text in Length Dimension

wps_clip_image-18777

Figure 2. 3D Wireframe Text in Dimension

wps_clip_image-31985

Figure 3. 3D Shading Text in Dimension

2.FreeType Usage

在FreeType的官網上有詳細的教程說明FreeType的用法,網址為:https://www.freetype.org/freetype2/docs/tutorial/index.html

主要的步驟如下:

v 包含頭文件 Header Files;

v 庫的初始化 Library Initialization;

v 加載字體 Loading a Font Face;

v 訪問字體數據 Accessing the Face Data;

v 設置當前像素大小 Setting the Current Pixel Size;

v 加載文字 Loading a Glyph Image;

v 簡單的顯示 Simple Text Rendering; 

下面代碼是上述過程的一個實現,忽略了錯誤處理:

#include <ft2build.h>
#include FT_FREETYPE_H
#pragma comment(lib, "freetype.lib")
void test(void)
{
    FT_Face aFace = NULL;
    FT_Library aLibrary = NULL;
    // Library Initialization.
    FT_Init_FreeType(&aLibrary);
    // Loading a Font Face.
    FT_New_Face(aLibrary, "C:/Windows/Fonts/arial.ttf", 0, &aFace);
    // Setting the Current Pixel Size.
    FT_Set_Char_Size(
          aFace,    /* handle to face object           */
          0,       /* char_width in 1/64th of points  */
          16*64,   /* char_height in 1/64th of points */
          300,     /* horizontal device resolution    */
          300 );   /* vertical device resolution      */
    // Loading a Glyph Image
    // a. Converting a Character Code Into a Glyph Index
    FT_UInt aGlyphIndex = FT_Get_Char_Index( aFace, 'A' );
    // b. Loading a Glyph From the Face
    // Once you have a glyph index, you can load the corresponding glyph image.
    FT_Load_Glyph(
          aFace,            /* handle to face object */
          aGlyphIndex,      /* glyph index           */
          FT_LOAD_DEFAULT); /* load flags            */
    // Simple Text Rendering
    FT_GlyphSlot aGlyphSlot = aFace->glyph;
}
int main(int argc, char* argv[])
{
    test();
    return 0;
}

 

wps_clip_image-11299

調試程序可以看出Face中已經有了一些數據。

3.FreeType Outlines

FreeType中的一個文字輪廓Outline是由二維空間閉合的線圍成。每一個輪廓線是由一系列的直線段和Bezier曲線組成。根據字體文件格式的不同,他們可能是二階或三階多項式。二階的通常稱為quadratic或conic弧,他們用于TrueType格式。三階的稱為cubic弧,通常用于PostScript Type1, CFF, 和CFF2格式中。詳細描述見:

https://www.freetype.org/freetype2/docs/glyphs/glyphs-6.html

Bezier曲線是B樣條曲線的一個特例,他的特點就是曲線的階數與控制點的個數相關,即給定控制頂點就可以確定Bezier曲線。所以OpenCASCADE中對于Bezier曲線有這樣的構造函數:

wps_clip_image-28489

每一段曲線弧都由起點start,終點end和控制頂點control points來描述。描述輪廓線的每個點都有一個特定的標記Tag來區別是線段還是Bezier曲線。

wps_clip_image-26515

wps_clip_image-23987

兩個連續的on點確定了線段的兩個端點;

在兩個on點之間的一個conic off點組成了一個conic Bezier曲線;

在兩個on點之間的兩個cubic off點組成了一個cubic Bezier曲線;

理解了上述內容就可以得到文字的輪廓線了。OpenCASCADE中對輪廓線的處理代碼如下所示:

// =======================================================================
// function : renderGlyph
// purpose  :
// =======================================================================
Standard_Boolean Font_BRepFont::renderGlyph (const Standard_Utf32Char theChar,
                                             TopoDS_Shape&            theShape)
{
  theShape.Nullify();
  if (!loadGlyph (theChar)
   || myFTFace->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
  {
    return Standard_False;
  }
  else if (myCache.Find (theChar, theShape))
  {
    return !theShape.IsNull();
  }
  FT_Outline& anOutline = myFTFace->glyph->outline;
  if (!anOutline.n_contours)
    return Standard_False;
  TopLoc_Location aLoc;
  TopoDS_Face aFaceDraft;
  myBuilder.MakeFace (aFaceDraft, mySurface, myPrecision);
  // Get orientation is useless since it doesn't retrieve any in-font information and just computes orientation.
  // Because it fails in some cases - leave this to ShapeFix.
  //const FT_Orientation anOrient = FT_Outline_Get_Orientation (&anOutline);
  for (short aContour = 0, aStartIndex = 0; aContour < anOutline.n_contours; ++aContour)
  {
    const FT_Vector* aPntList = &anOutline.points[aStartIndex];
    const char* aTags      = &anOutline.tags[aStartIndex];
    const short anEndIndex = anOutline.contours[aContour];
    const short aPntsNb    = (anEndIndex - aStartIndex) + 1;
    aStartIndex = anEndIndex + 1;
    if (aPntsNb < 3)
    {
      // closed contour can not be constructed from < 3 points
      continue;
    }
    BRepBuilderAPI_MakeWire aWireMaker;
    gp_XY aPntPrev;
    gp_XY aPntCurr = readFTVec (aPntList[aPntsNb - 1]);
    gp_XY aPntNext = readFTVec (aPntList[0]);
    Standard_Integer aLinePnts = (FT_CURVE_TAG(aTags[aPntsNb - 1]) == FT_Curve_Tag_On) ? 1 : 0;
    gp_XY aPntLine1 = aPntCurr;
    // see http://freetype.sourceforge.net/freetype2/docs/glyphs/glyphs-6.html
    // for a full description of FreeType tags.
    for (short aPntId = 0; aPntId < aPntsNb; ++aPntId)
    {
      aPntPrev = aPntCurr;
      aPntCurr = aPntNext;
      aPntNext = readFTVec (aPntList[(aPntId + 1) % aPntsNb]);
      // process tags
      if (FT_CURVE_TAG(aTags[aPntId]) == FT_Curve_Tag_On)
      {
        if (aLinePnts < 1)
        {
          aPntLine1 = aPntCurr;
          aLinePnts = 1;
          continue;
        }
        const gp_XY         aDirVec  = aPntCurr - aPntLine1;
        const Standard_Real aLen     = aDirVec.Modulus();
        if (aLen <= myPrecision)
        {
          aPntLine1 = aPntCurr;
          aLinePnts = 1;
          continue;
        }
        if (myIsCompositeCurve)
        {
          Handle(Geom2d_TrimmedCurve) aLine = GCE2d_MakeSegment (gp_Pnt2d (aPntLine1), gp_Pnt2d (aPntCurr));
          myConcatMaker.Add (aLine, myPrecision);
        }
        else
        {
          Handle(Geom_Curve)  aCurve3d;
          Handle(Geom2d_Line) aCurve2d = new Geom2d_Line (gp_Pnt2d (aPntLine1), gp_Dir2d (aDirVec));
          if (to3d (aCurve2d, GeomAbs_C1, aCurve3d))
          {
            TopoDS_Edge anEdge = BRepLib_MakeEdge (aCurve3d, 0.0, aLen);
            myBuilder.UpdateEdge (anEdge, aCurve2d, mySurface, aLoc, myPrecision);
            aWireMaker.Add (anEdge);
          }
        }
        aPntLine1 = aPntCurr;
      }
      else if (FT_CURVE_TAG(aTags[aPntId]) == FT_Curve_Tag_Conic)
      {
        aLinePnts = 0;
        gp_XY aPntPrev2 = aPntPrev;
        gp_XY aPntNext2 = aPntNext;
        // previous point is either the real previous point (an "on" point),
        // or the midpoint between the current one and the previous "conic off" point
        if (FT_CURVE_TAG(aTags[(aPntId - 1 + aPntsNb) % aPntsNb]) == FT_Curve_Tag_Conic)
        {
          aPntPrev2 = (aPntCurr + aPntPrev) * 0.5;
        }
        // next point is either the real next point or the midpoint
        if (FT_CURVE_TAG(aTags[(aPntId + 1) % aPntsNb]) == FT_Curve_Tag_Conic)
        {
          aPntNext2 = (aPntCurr + aPntNext) * 0.5;
        }
        my3Poles.SetValue (1, aPntPrev2);
        my3Poles.SetValue (2, aPntCurr);
        my3Poles.SetValue (3, aPntNext2);
        Handle(Geom2d_BezierCurve) aBezierArc = new Geom2d_BezierCurve (my3Poles);
        if (myIsCompositeCurve)
        {
          myConcatMaker.Add (aBezierArc, myPrecision);
        }
        else
        {
          Handle(Geom_Curve) aCurve3d;
          if (to3d (aBezierArc, GeomAbs_C1, aCurve3d))
          {
            TopoDS_Edge anEdge = BRepLib_MakeEdge (aCurve3d);
            myBuilder.UpdateEdge (anEdge, aBezierArc, mySurface, aLoc, myPrecision);
            aWireMaker.Add (anEdge);
          }
        }
      }
      else if (FT_CURVE_TAG(aTags[aPntId])                 == FT_Curve_Tag_Cubic
            && FT_CURVE_TAG(aTags[(aPntId + 1) % aPntsNb]) == FT_Curve_Tag_Cubic)
      {
        aLinePnts = 0;
        my4Poles.SetValue (1, aPntPrev);
        my4Poles.SetValue (2, aPntCurr);
        my4Poles.SetValue (3, aPntNext);
        my4Poles.SetValue (4, gp_Pnt2d(readFTVec (aPntList[(aPntId + 2) % aPntsNb])));
        Handle(Geom2d_BezierCurve) aBezier = new Geom2d_BezierCurve (my4Poles);
        if (myIsCompositeCurve)
        {
          myConcatMaker.Add (aBezier, myPrecision);
        }
        else
        {
          Handle(Geom_Curve) aCurve3d;
          if (to3d (aBezier, GeomAbs_C1, aCurve3d))
          {
            TopoDS_Edge anEdge = BRepLib_MakeEdge (aCurve3d);
            myBuilder.UpdateEdge (anEdge, aBezier, mySurface, aLoc, myPrecision);
            aWireMaker.Add (anEdge);
          }
        }
      }
    }
    if (myIsCompositeCurve)
    {
      Handle(Geom2d_BSplineCurve) aDraft2d = myConcatMaker.BSplineCurve();
      if (aDraft2d.IsNull())
      {
        continue;
      }
      const gp_Pnt2d aFirstPnt = aDraft2d->StartPoint();
      const gp_Pnt2d aLastPnt  = aDraft2d->EndPoint();
      if (!aFirstPnt.IsEqual (aLastPnt, myPrecision))
      {
        Handle(Geom2d_TrimmedCurve) aLine = GCE2d_MakeSegment (aLastPnt, aFirstPnt);
        myConcatMaker.Add (aLine, myPrecision);
      }
      Handle(Geom2d_BSplineCurve) aCurve2d = myConcatMaker.BSplineCurve();
      Handle(Geom_Curve)          aCurve3d;
      if (to3d (aCurve2d, GeomAbs_C0, aCurve3d))
      {
        TopoDS_Edge anEdge = BRepLib_MakeEdge (aCurve3d);
        myBuilder.UpdateEdge (anEdge, aCurve2d, mySurface, aLoc, myPrecision);
        aWireMaker.Add (anEdge);
      }
      myConcatMaker.Clear();
    }
    else
    {
      if (!aWireMaker.IsDone())
      {
        continue;
      }
      TopoDS_Vertex aFirstV, aLastV;
      TopExp::Vertices (aWireMaker.Wire(), aFirstV, aLastV);
      gp_Pnt aFirstPoint = BRep_Tool::Pnt (aFirstV);
      gp_Pnt aLastPoint  = BRep_Tool::Pnt (aLastV);
      if (!aFirstPoint.IsEqual (aLastPoint, myPrecision))
      {
        aWireMaker.Add (BRepLib_MakeEdge (aFirstV, aLastV));
      }
    }
    if (!aWireMaker.IsDone())
    {
      continue;
    }
    TopoDS_Wire aWireDraft = aWireMaker.Wire();
    //if (anOrient == FT_ORIENTATION_FILL_LEFT)
    //{
    // According to the TrueType specification, clockwise contours must be filled
    aWireDraft.Reverse();
    //}
    myBuilder.Add (aFaceDraft, aWireDraft);
  }
  myFixer.Init (aFaceDraft);
  myFixer.Perform();
  theShape = myFixer.Result();
  if (!theShape.IsNull()
  &&  theShape.ShapeType() != TopAbs_FACE)
  {
    // shape fix can not fix orientation within the single call
    TopoDS_Compound aComp;
    myBuilder.MakeCompound (aComp);
    for (TopExp_Explorer aFaceIter (theShape, TopAbs_FACE); aFaceIter.More(); aFaceIter.Next())
    {
      TopoDS_Face aFace = TopoDS::Face (aFaceIter.Current());
      myFixer.Init (aFace);
      myFixer.Perform();
      myBuilder.Add (aComp, myFixer.Result());
    }
    theShape = aComp;
  }
  myCache.Bind (theChar, theShape);
  return !theShape.IsNull();
}

 

4.Text 3D

在一些圖形庫中都可以生成三維文字,如下圖所示:

wps_clip_image-12745

理解了FreeType的用法后,實現上述功能也是很簡單的。這里簡要說明實現步驟:

l 使用FreeType得到文字的輪廓線;

l 將閉合的輪廓線生成Wire->Face;

l 將輪廓線生成的Face進行拉伸得到Solid體。

在OpenCASCADE中得到文字輪廓線生成的Face的類是:Font_BRepFont。下面給出示例得到指定文字的面。

#include <BRepTools.hxx>
#include <Font_BRepFont.hxx>
#include <Font_BRepTextBuilder.hxx>
#pragma comment(lib, "TKernel.lib")
#pragma comment(lib, "TKMath.lib")
#pragma comment(lib, "TKG2d.lib")
#pragma comment(lib, "TKG3d.lib")
#pragma comment(lib, "TKGeomBase.lib")
#pragma comment(lib, "TKGeomAlgo.lib")
#pragma comment(lib, "TKBRep.lib")
#pragma comment(lib, "TKTopAlgo.lib")
#pragma comment(lib, "TKService.lib")
void text2brep()
{
    Font_BRepFont aBrepFont("C:/Windows/Fonts/arial.ttf", 3.5);
    Font_BRepTextBuilder aTextBuilder;
    TopoDS_Shape aTextShape = aTextBuilder.Perform(aBrepFont, NCollection_String("eryar@163.com"));
    BRepTools::Dump(aTextShape, std::cout);
    BRepTools::Write(aTextShape, "d:/text.brep");
}
int main(int argc, char* argv[])
{
    text2brep();
    return 0;
}

在Draw Test Harness中顯示出文字的輪廓text.brep如下圖所示:

wps_clip_image-22486

如果要顯示出文字的填充效果,則需要有三角化工具將文字輪廓網格化。OpenCASCADE中將輪廓生成Wire->Face,即可以生成顯示數據了:

wps_clip_image-28082

5.Conclusion

FreeType的文字處理功能很強大,幾乎所有的三維造型內核中文字的處理都是使用的FreeType。

FreeType的文字輪廓使用了線段和Bezier曲線來表達,Bezier曲線是B樣條曲線的特例。理解Bezier曲線就可以自己繪制文字輪廓了。

FreeType使用簡單,可以方便得到文字的輪廓數據。將輪廓數據生成Face即可以拉伸出三維文字效果。

6.References

1. https://www.freetype.org/freetype2/docs/tutorial/index.html

2. http://m.shnenglu.com/eryar/archive/2014/08/17/OpenCascade_Text_Rendering.html

3. https://www.freetype.org/freetype2/docs/glyphs/glyphs-6.html

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            在线成人小视频| 午夜久久资源| 欧美高清视频在线播放| 欧美一区二区精品| 亚洲欧美三级伦理| 欧美一区=区| 久久九九免费视频| 麻豆精品精华液| 欧美激情综合网| 欧美性猛交99久久久久99按摩 | 欧美国产视频在线| 久久综合九色九九| 欧美插天视频在线播放| 亚洲欧洲在线播放| 亚洲电影在线播放| 一区二区三区三区在线| 欧美一站二站| 欧美精品乱人伦久久久久久| 国产精品日韩在线播放| 在线视频国内自拍亚洲视频| 99精品国产99久久久久久福利| 亚洲一区二区三区在线看 | 欧美日本一道本| 国产精品亚洲综合一区在线观看| 国产自产精品| 国产精品99久久久久久白浆小说 | 欧美国产高清| 亚洲性视频网站| 欧美国产免费| 精品动漫3d一区二区三区免费版| 亚洲狼人综合| 久久久久久久欧美精品| 亚洲精品精选| 久久久久综合一区二区三区| 国产精品第三页| 亚洲美女av电影| 女女同性女同一区二区三区91| 日韩一区二区精品在线观看| 久久精品中文字幕免费mv| 国产精品v欧美精品∨日韩| 亚洲国产欧美一区二区三区久久| 午夜精品一区二区在线观看| 亚洲欧洲免费视频| 麻豆精品网站| 激情自拍一区| 久久婷婷av| 久久av一区二区| 国产精品久久久爽爽爽麻豆色哟哟| 一区在线电影| 卡通动漫国产精品| 欧美一区在线看| 国产精品日日摸夜夜添夜夜av | 欧美日韩国产色综合一二三四 | 亚洲欧美视频一区二区三区| 欧美日韩第一区| 91久久精品国产91性色tv| 亚洲自拍偷拍一区| 久久午夜色播影院免费高清| 最近中文字幕日韩精品| 欧美一区二区精品久久911| 国产精品户外野外| 亚洲影院色在线观看免费| 99国产精品久久久久老师| 欧美日韩一区二区视频在线观看 | 亚洲高清av| 欧美成人免费在线观看| 另类尿喷潮videofree | 久久久久九九九| 激情久久综合| 欧美大片va欧美在线播放| 蜜桃av一区二区| 亚洲精品在线二区| 亚洲啪啪91| 免费在线成人av| 亚洲精品日韩久久| 日韩一级裸体免费视频| 国产免费成人在线视频| 久久久亚洲高清| 美女免费视频一区| 一本色道久久综合狠狠躁篇怎么玩 | 午夜欧美精品久久久久久久| 中国av一区| 好看的亚洲午夜视频在线| 亚洲电影中文字幕| 国产精品国产a级| 另类综合日韩欧美亚洲| 欧美精品免费观看二区| 欧美亚洲自偷自偷| 久久夜色精品国产| 亚洲一区三区在线观看| 欧美在线观看天堂一区二区三区| 一区二区在线免费观看| 亚洲人成7777| 国产亚洲欧美激情| 欧美激情第三页| 国产精品欧美在线| 欧美黄在线观看| 欧美午夜电影在线| 女仆av观看一区| 国产精品男gay被猛男狂揉视频| 另类欧美日韩国产在线| 欧美亚韩一区| 欧美成人视屏| 国产精品美女999| 久久综合精品一区| 国产精品女主播一区二区三区| 欧美肥婆在线| 国产欧美日韩视频| 夜夜嗨av一区二区三区中文字幕 | 亚洲欧美综合另类中字| 久久一区二区三区国产精品 | 1024日韩| aa级大片欧美三级| 国产一区欧美| 亚洲色图自拍| 亚洲精品视频在线观看免费| 欧美亚洲日本国产| 一区二区三区精品久久久| 久久九九免费| 欧美在线观看视频一区二区三区| 欧美极品在线播放| 久久嫩草精品久久久精品一| 国产精品久久久久久久久久三级| 亚洲国产精品一区二区www| 国语自产偷拍精品视频偷| 亚洲欧美日本视频在线观看| 亚洲专区一区二区三区| 欧美日韩一区二区三区在线视频| 亚洲国产成人久久综合一区| 亚洲成色www久久网站| 久久久99免费视频| 久久免费视频在线观看| 国产一区在线看| 欧美一区二区成人6969| 久久精品午夜| 黑人一区二区| 久久激情视频免费观看| 久久亚洲二区| 亚洲国产高清高潮精品美女| 久久久久国产一区二区三区| 久热精品视频在线观看一区| 尤物九九久久国产精品的特点 | 中文在线不卡| 亚洲欧美在线一区| 国产日韩欧美精品| 久久国产精品99精品国产| 久久久久久网站| 亚洲国产精品成人| 欧美精品午夜| 亚洲影院色无极综合| 欧美影院在线播放| 国内精品久久久久影院色| 香蕉久久一区二区不卡无毒影院| 久久精品夜色噜噜亚洲a∨| 国产亚洲视频在线观看| 久久久www免费人成黑人精品 | 亚洲国产成人tv| 欧美精品日韩综合在线| 在线一区二区三区四区| 久久久久久综合网天天| 亚洲欧洲日韩综合二区| 欧美人与禽猛交乱配| 亚洲一区二区日本| 免费成人高清视频| 亚洲天堂男人| 国产亚洲aⅴaaaaaa毛片| 免费久久99精品国产自| 一区二区三区成人| 久久久夜精品| 99热免费精品| 国产日韩成人精品| 欧美国产激情| 性欧美大战久久久久久久久| 欧美电影免费观看| 亚洲欧美久久| 狠狠色综合日日| 亚洲欧美日韩一区| 欧美高清视频免费观看| 亚洲专区一二三| 伊人影院久久| 国产精品国产三级国产普通话三级| 亚洲在线视频观看| 免费日韩视频| 亚洲欧美国产一区二区三区| 在线成人激情| 国产欧美日韩一区| 欧美日韩一区二区视频在线观看| 久久精品1区| 亚洲一区二区少妇| 亚洲经典一区| 米奇777在线欧美播放| 午夜精品久久久久久久久久久久| 亚洲黄色精品| 好吊一区二区三区| 国产日韩欧美夫妻视频在线观看| 欧美三级视频在线观看| 欧美大片va欧美在线播放| 久久久亚洲精品一区二区三区| 午夜精品三级视频福利| 宅男噜噜噜66国产日韩在线观看|