0031458: Visualization - refine classes across Prs3d and StdPrs packages
[occt.git] / src / StdPrs / StdPrs_BRepFont.cxx
CommitLineData
b514beda 1// Created on: 2013-09-16
d5f74e42 2// Copyright (c) 2013-2014 OPEN CASCADE SAS
b514beda 3//
973c2be1 4// This file is part of Open CASCADE Technology software library.
b514beda 5//
d5f74e42 6// This library is free software; you can redistribute it and/or modify it under
7// the terms of the GNU Lesser General Public License version 2.1 as published
973c2be1 8// by the Free Software Foundation, with special exception defined in the file
9// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10// distribution for complete text of the license and disclaimer of any warranty.
b514beda 11//
973c2be1 12// Alternatively, this file may be used under the terms of Open CASCADE
13// commercial license or contractual agreement.
b514beda 14
7f24b768 15#include <StdPrs_BRepFont.hxx>
b514beda 16
17#include <BRep_Tool.hxx>
3388cf17 18#include <BRepTopAdaptor_FClass2d.hxx>
b514beda 19#include <BRepBuilderAPI_MakeFace.hxx>
20#include <BRepBuilderAPI_MakeWire.hxx>
21#include <BRepLib_MakeEdge.hxx>
f9801cf9 22#include <Font_FTLibrary.hxx>
1bbd7c79 23#include <Font_FontMgr.hxx>
ac84fcf6 24#include <Font_TextFormatter.hxx>
b514beda 25#include <GCE2d_MakeSegment.hxx>
26#include <GC_MakeSegment.hxx>
27#include <Geom_BezierCurve.hxx>
28#include <Geom_BSplineCurve.hxx>
c04c30b3 29#include <Geom2d_TrimmedCurve.hxx>
b514beda 30#include <Geom_Plane.hxx>
31#include <Geom2d_BezierCurve.hxx>
32#include <Geom2d_BSplineCurve.hxx>
543a9964 33#include <Geom2d_TrimmedCurve.hxx>
b514beda 34#include <Geom2d_Line.hxx>
35#include <GeomAPI.hxx>
36#include <GeomAdaptor_HSurface.hxx>
37#include <GeomLib.hxx>
38#include <gp_Pln.hxx>
b514beda 39#include <TColGeom2d_HSequenceOfBoundedCurve.hxx>
40#include <TCollection_AsciiString.hxx>
41#include <TCollection_HAsciiString.hxx>
42#include <TopExp.hxx>
43#include <TopExp_Explorer.hxx>
44#include <TopoDS.hxx>
45#include <TopoDS_Compound.hxx>
46#include <TopoDS_Vertex.hxx>
3388cf17 47#include <TopTools_DataMapOfShapeInteger.hxx>
48#include <TopTools_DataMapOfShapeSequenceOfShape.hxx>
b514beda 49
f9801cf9 50#include <ft2build.h>
51#include FT_FREETYPE_H
b514beda 52#include FT_OUTLINE_H
53
7f24b768 54IMPLEMENT_STANDARD_RTTIEXT(StdPrs_BRepFont, Font_FTFont)
92efcf78 55
b514beda 56namespace
57{
58 // pre-defined font rendering options
59 static const unsigned int THE_FONT_SIZE = 72;
60 static const unsigned int THE_RESOLUTION_DPI = 4800;
1bbd7c79 61 static const Font_FTFontParams THE_FONT_PARAMS (THE_FONT_SIZE, THE_RESOLUTION_DPI);
b514beda 62
63 // compute scaling factor for specified font size
64 inline Standard_Real getScale (const Standard_Real theSize)
65 {
66 return theSize / Standard_Real(THE_FONT_SIZE) * 72.0 / Standard_Real(THE_RESOLUTION_DPI);
67 }
68
f9801cf9 69 //! Auxiliary method to convert FT_Vector to gp_XY
70 static gp_XY readFTVec (const FT_Vector& theVec,
151da08b 71 const Standard_Real theScaleUnits,
72 const Standard_Real theWidthScaling = 1.0)
f9801cf9 73 {
151da08b 74 return gp_XY (theScaleUnits * Standard_Real(theVec.x) * theWidthScaling / 64.0, theScaleUnits * Standard_Real(theVec.y) / 64.0);
f9801cf9 75 }
76
3388cf17 77 //! Auxiliary method for classification wire theW2 with respect to wire theW1
78 static TopAbs_State classifyWW (const TopoDS_Wire& theW1,
79 const TopoDS_Wire& theW2,
80 const TopoDS_Face& theF)
81 {
82 TopAbs_State aRes = TopAbs_UNKNOWN;
83
84 TopoDS_Face aF = TopoDS::Face (theF.EmptyCopied());
85 aF.Orientation (TopAbs_FORWARD);
86 BRep_Builder aB;
87 aB.Add (aF, theW1);
88 BRepTopAdaptor_FClass2d aClass2d (aF, ::Precision::PConfusion());
89 for (TopoDS_Iterator anEdgeIter (theW2); anEdgeIter.More(); anEdgeIter.Next())
90 {
91 const TopoDS_Edge& anEdge = TopoDS::Edge (anEdgeIter.Value());
92 Standard_Real aPFirst = 0.0, aPLast = 0.0;
93 Handle(Geom2d_Curve) aCurve2d = BRep_Tool::CurveOnSurface (anEdge, theF, aPFirst, aPLast);
94 if (aCurve2d.IsNull())
95 {
96 continue;
97 }
98
99 gp_Pnt2d aPnt2d = aCurve2d->Value ((aPFirst + aPLast) / 2.0);
100 TopAbs_State aState = aClass2d.Perform (aPnt2d, Standard_False);
101 if (aState == TopAbs_OUT
102 || aState == TopAbs_IN)
103 {
104 if (aRes == TopAbs_UNKNOWN)
105 {
106 aRes = aState;
107 }
108 else if (aRes != aState)
109 {
110 return TopAbs_UNKNOWN;
111 }
112 }
113 }
114 return aRes;
115 }
116
a3f6f591 117}
b514beda 118
119// =======================================================================
120// function : Constructor
121// purpose :
122// =======================================================================
7f24b768 123StdPrs_BRepFont::StdPrs_BRepFont ()
b514beda 124: myPrecision (Precision::Confusion()),
125 myScaleUnits (1.0),
126 myIsCompositeCurve (Standard_False),
127 my3Poles (1, 3),
128 my4Poles (1, 4)
129{
130 init();
131}
132
133// =======================================================================
134// function : init
135// purpose :
136// =======================================================================
7f24b768 137void StdPrs_BRepFont::init()
b514beda 138{
139 mySurface = new Geom_Plane (gp_Pln (gp::XOY()));
140 myCurve2dAdaptor = new Geom2dAdaptor_HCurve();
543a9964 141 Handle(Adaptor3d_HSurface) aSurfAdaptor = new GeomAdaptor_HSurface (mySurface);
b514beda 142 myCurvOnSurf.Load (aSurfAdaptor);
b514beda 143}
144
145// =======================================================================
146// function : Constructor
147// purpose :
148// =======================================================================
7f24b768 149StdPrs_BRepFont::StdPrs_BRepFont (const NCollection_String& theFontPath,
150 const Standard_Real theSize,
151 const Standard_Integer theFaceId)
b514beda 152: myPrecision (Precision::Confusion()),
153 myScaleUnits (1.0),
154 myIsCompositeCurve (Standard_False),
155 my3Poles (1, 3),
156 my4Poles (1, 4)
157{
158 init();
159 if (theSize <= myPrecision * 100.0)
160 {
161 return;
162 }
163
164 myScaleUnits = getScale (theSize);
9a90a452 165 Font_FTFont::Init (theFontPath.ToCString(), THE_FONT_PARAMS, theFaceId);
b514beda 166}
167
168// =======================================================================
169// function : Constructor
170// purpose :
171// =======================================================================
7f24b768 172StdPrs_BRepFont::StdPrs_BRepFont (const NCollection_String& theFontName,
173 const Font_FontAspect theFontAspect,
174 const Standard_Real theSize,
175 const Font_StrictLevel theStrictLevel)
b514beda 176: myPrecision (Precision::Confusion()),
177 myScaleUnits (1.0),
178 myIsCompositeCurve (Standard_False),
179 my3Poles (1, 3),
180 my4Poles (1, 4)
181{
182 init();
183 if (theSize <= myPrecision * 100.0)
184 {
185 return;
186 }
187
188 myScaleUnits = getScale (theSize);
1bbd7c79 189 Font_FTFont::FindAndInit (theFontName.ToCString(), theFontAspect, THE_FONT_PARAMS, theStrictLevel);
b514beda 190}
191
192// =======================================================================
193// function : Release
194// purpose :
195// =======================================================================
7f24b768 196void StdPrs_BRepFont::Release()
b514beda 197{
198 myCache.Clear();
199 Font_FTFont::Release();
200}
201
202// =======================================================================
203// function : SetCompositeCurveMode
204// purpose :
205// =======================================================================
7f24b768 206void StdPrs_BRepFont::SetCompositeCurveMode (const Standard_Boolean theToConcatenate)
b514beda 207{
208 if (myIsCompositeCurve != theToConcatenate)
209 {
210 myIsCompositeCurve = theToConcatenate;
211 myCache.Clear();
212 }
213}
214
215// =======================================================================
216// function : Init
217// purpose :
218// =======================================================================
7f24b768 219bool StdPrs_BRepFont::Init (const NCollection_String& theFontPath,
220 const Standard_Real theSize,
221 const Standard_Integer theFaceId)
b514beda 222{
223 if (theSize <= myPrecision * 100.0)
224 {
225 return false;
226 }
227
228 myScaleUnits = getScale (theSize);
9a90a452 229 return Font_FTFont::Init (theFontPath.ToCString(), THE_FONT_PARAMS, theFaceId);
b514beda 230}
231
232// =======================================================================
1bbd7c79 233// function : FindAndInit
b514beda 234// purpose :
235// =======================================================================
7f24b768 236bool StdPrs_BRepFont::FindAndInit (const TCollection_AsciiString& theFontName,
237 const Font_FontAspect theFontAspect,
238 const Standard_Real theSize,
239 const Font_StrictLevel theStrictLevel)
b514beda 240{
241 if (theSize <= myPrecision * 100.0)
242 {
243 return false;
244 }
245
246 myScaleUnits = getScale (theSize);
1bbd7c79 247 return Font_FTFont::FindAndInit (theFontName.ToCString(), theFontAspect, THE_FONT_PARAMS, theStrictLevel);
b514beda 248}
249
250// =======================================================================
251// function : RenderGlyph
252// purpose :
253// =======================================================================
7f24b768 254TopoDS_Shape StdPrs_BRepFont::RenderGlyph (const Standard_Utf32Char& theChar)
b514beda 255{
256 TopoDS_Shape aShape;
257 Standard_Mutex::Sentry aSentry (myMutex);
258 renderGlyph (theChar, aShape);
259 return aShape;
260}
261
262// =======================================================================
263// function : to3d
264// purpose :
265// =======================================================================
7f24b768 266bool StdPrs_BRepFont::to3d (const Handle(Geom2d_Curve)& theCurve2d,
267 const GeomAbs_Shape theContinuity,
268 Handle(Geom_Curve)& theCurve3d)
b514beda 269{
270 Standard_Real aMaxDeviation = 0.0;
271 Standard_Real anAverDeviation = 0.0;
272 myCurve2dAdaptor->ChangeCurve2d().Load (theCurve2d);
543a9964 273 const Handle(Adaptor2d_HCurve2d)& aCurve = myCurve2dAdaptor; // to avoid ambiguity
274 myCurvOnSurf.Load (aCurve);
b514beda 275 GeomLib::BuildCurve3d (myPrecision, myCurvOnSurf,
276 myCurve2dAdaptor->FirstParameter(), myCurve2dAdaptor->LastParameter(),
277 theCurve3d, aMaxDeviation, anAverDeviation, theContinuity);
278 return !theCurve3d.IsNull();
279}
280
3388cf17 281
282// =======================================================================
283// function : buildFaces
284// purpose :
285// =======================================================================
7f24b768 286Standard_Boolean StdPrs_BRepFont::buildFaces (const NCollection_Sequence<TopoDS_Wire>& theWires,
287 TopoDS_Shape& theRes)
3388cf17 288{
289 // classify wires
290 NCollection_DataMap<TopoDS_Shape, NCollection_Sequence<TopoDS_Wire>, TopTools_ShapeMapHasher> aMapOutInts;
291 TopTools_DataMapOfShapeInteger aMapNbOuts;
292 TopoDS_Face aF;
293 myBuilder.MakeFace (aF, mySurface, myPrecision);
294 Standard_Integer aWireIter1Index = 1;
295 for (NCollection_Sequence<TopoDS_Wire>::Iterator aWireIter1 (theWires); aWireIter1.More(); ++aWireIter1Index, aWireIter1.Next())
296 {
297 const TopoDS_Wire& aW1 = aWireIter1.Value();
298 if (!aMapNbOuts.IsBound (aW1))
299 {
300 const Standard_Integer aNbOuts = 0;
301 aMapNbOuts.Bind (aW1, aNbOuts);
302 }
303
304 NCollection_Sequence<TopoDS_Wire>* anIntWs = aMapOutInts.Bound (aW1, NCollection_Sequence<TopoDS_Wire>());
305 Standard_Integer aWireIter2Index = 1;
306 for (NCollection_Sequence<TopoDS_Wire>::Iterator aWireIter2 (theWires); aWireIter2.More(); ++aWireIter2Index, aWireIter2.Next())
307 {
308 if (aWireIter1Index == aWireIter2Index)
309 {
310 continue;
311 }
312
313 const TopoDS_Wire& aW2 = aWireIter2.Value();
314 const TopAbs_State aClass = classifyWW (aW1, aW2, aF);
315 if (aClass == TopAbs_IN)
316 {
317 anIntWs->Append (aW2);
318 if (Standard_Integer* aNbOutsPtr = aMapNbOuts.ChangeSeek (aW2))
319 {
320 ++(*aNbOutsPtr);
321 }
322 else
323 {
324 const Standard_Integer aNbOuts = 1;
325 aMapNbOuts.Bind (aW2, aNbOuts);
326 }
327 }
328 }
329 }
330
331 // check out wires and remove "not out" wires from maps
332 for (TopTools_DataMapIteratorOfDataMapOfShapeInteger anOutIter (aMapNbOuts); anOutIter.More(); anOutIter.Next())
333 {
334 const Standard_Integer aTmp = anOutIter.Value() % 2;
335 if (aTmp > 0)
336 {
337 // not out wire
338 aMapOutInts.UnBind (anOutIter.Key());
339 }
340 }
341
342 // create faces for out wires
343 TopTools_MapOfShape anUsedShapes;
344 TopoDS_Compound aFaceComp;
345 myBuilder.MakeCompound (aFaceComp);
346 for (; !aMapOutInts.IsEmpty(); )
347 {
348 // find out wire with max number of outs
349 TopoDS_Shape aW;
350 Standard_Integer aMaxNbOuts = -1;
351 for (NCollection_DataMap<TopoDS_Shape, NCollection_Sequence<TopoDS_Wire>, TopTools_ShapeMapHasher>::Iterator itMOI (aMapOutInts);
352 itMOI.More(); itMOI.Next())
353 {
354 const TopoDS_Shape& aKey = itMOI.Key();
355 const Standard_Integer aNbOuts = aMapNbOuts.Find (aKey);
356 if (aNbOuts > aMaxNbOuts)
357 {
358 aMaxNbOuts = aNbOuts;
359 aW = aKey;
360 }
361 }
362
363 // create face for selected wire
364 TopoDS_Face aNewF;
365 myBuilder.MakeFace (aNewF, mySurface, myPrecision);
366 myBuilder.Add (aNewF, aW);
367 anUsedShapes.Add (aW);
368 const NCollection_Sequence<TopoDS_Wire>& anIns = aMapOutInts.Find (aW);
369 for (NCollection_Sequence<TopoDS_Wire>::Iterator aWireIter (anIns); aWireIter.More(); aWireIter.Next())
370 {
371 TopoDS_Wire aWin = aWireIter.Value();
372 if (anUsedShapes.Contains (aWin))
373 {
374 continue;
375 }
376
377 aWin.Reverse();
378 myBuilder.Add (aNewF, aWin);
379 anUsedShapes.Add (aWin);
380 }
381
382 myBuilder.Add (aFaceComp, aNewF);
383 aMapOutInts.UnBind (aW);
384 }
385
386 if (aFaceComp.NbChildren() == 0)
387 {
388 return Standard_False;
389 }
390
391 if (aFaceComp.NbChildren() == 1)
392 {
393 theRes = TopoDS_Iterator (aFaceComp).Value();
394 }
395 else
396 {
397 theRes = aFaceComp;
398 }
399 return Standard_True;
400}
401
b514beda 402// =======================================================================
403// function : renderGlyph
404// purpose :
405// =======================================================================
7f24b768 406Standard_Boolean StdPrs_BRepFont::renderGlyph (const Standard_Utf32Char theChar,
407 TopoDS_Shape& theShape)
b514beda 408{
409 theShape.Nullify();
410 if (!loadGlyph (theChar)
912761ea 411 || myActiveFTFace->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
b514beda 412 {
413 return Standard_False;
414 }
415 else if (myCache.Find (theChar, theShape))
416 {
417 return !theShape.IsNull();
418 }
419
912761ea 420 const FT_Outline& anOutline = myActiveFTFace->glyph->outline;
be7d4aa2 421 if (!anOutline.n_contours)
422 return Standard_False;
423
b514beda 424 TopLoc_Location aLoc;
3388cf17 425 NCollection_Sequence<TopoDS_Wire> aWires;
e4f0cc46 426 TopoDS_Compound aFaceCompDraft;
be7d4aa2 427
b514beda 428 // Get orientation is useless since it doesn't retrieve any in-font information and just computes orientation.
429 // Because it fails in some cases - leave this to ShapeFix.
430 //const FT_Orientation anOrient = FT_Outline_Get_Orientation (&anOutline);
431 for (short aContour = 0, aStartIndex = 0; aContour < anOutline.n_contours; ++aContour)
432 {
433 const FT_Vector* aPntList = &anOutline.points[aStartIndex];
434 const char* aTags = &anOutline.tags[aStartIndex];
435 const short anEndIndex = anOutline.contours[aContour];
436 const short aPntsNb = (anEndIndex - aStartIndex) + 1;
437 aStartIndex = anEndIndex + 1;
1bbd7c79 438 if (aPntsNb < 3 && !myFontParams.IsSingleStrokeFont)
b514beda 439 {
440 // closed contour can not be constructed from < 3 points
441 continue;
442 }
443
444 BRepBuilderAPI_MakeWire aWireMaker;
445
446 gp_XY aPntPrev;
151da08b 447 gp_XY aPntCurr = readFTVec (aPntList[aPntsNb - 1], myScaleUnits, myWidthScaling);
448 gp_XY aPntNext = readFTVec (aPntList[0], myScaleUnits, myWidthScaling);
b514beda 449
1bbd7c79 450 bool isLineSeg = !myFontParams.IsSingleStrokeFont
e4f0cc46 451 && FT_CURVE_TAG(aTags[aPntsNb - 1]) == FT_Curve_Tag_On;
b514beda 452 gp_XY aPntLine1 = aPntCurr;
453
454 // see http://freetype.sourceforge.net/freetype2/docs/glyphs/glyphs-6.html
455 // for a full description of FreeType tags.
456 for (short aPntId = 0; aPntId < aPntsNb; ++aPntId)
457 {
458 aPntPrev = aPntCurr;
459 aPntCurr = aPntNext;
151da08b 460 aPntNext = readFTVec (aPntList[(aPntId + 1) % aPntsNb], myScaleUnits, myWidthScaling);
b514beda 461
462 // process tags
463 if (FT_CURVE_TAG(aTags[aPntId]) == FT_Curve_Tag_On)
464 {
e4f0cc46 465 if (!isLineSeg)
b514beda 466 {
467 aPntLine1 = aPntCurr;
e4f0cc46 468 isLineSeg = true;
b514beda 469 continue;
470 }
471
472 const gp_XY aDirVec = aPntCurr - aPntLine1;
473 const Standard_Real aLen = aDirVec.Modulus();
474 if (aLen <= myPrecision)
475 {
476 aPntLine1 = aPntCurr;
e4f0cc46 477 isLineSeg = true;
b514beda 478 continue;
479 }
480
481 if (myIsCompositeCurve)
482 {
483 Handle(Geom2d_TrimmedCurve) aLine = GCE2d_MakeSegment (gp_Pnt2d (aPntLine1), gp_Pnt2d (aPntCurr));
484 myConcatMaker.Add (aLine, myPrecision);
485 }
486 else
487 {
488 Handle(Geom_Curve) aCurve3d;
489 Handle(Geom2d_Line) aCurve2d = new Geom2d_Line (gp_Pnt2d (aPntLine1), gp_Dir2d (aDirVec));
490 if (to3d (aCurve2d, GeomAbs_C1, aCurve3d))
491 {
492 TopoDS_Edge anEdge = BRepLib_MakeEdge (aCurve3d, 0.0, aLen);
493 myBuilder.UpdateEdge (anEdge, aCurve2d, mySurface, aLoc, myPrecision);
494 aWireMaker.Add (anEdge);
495 }
496 }
497 aPntLine1 = aPntCurr;
498 }
499 else if (FT_CURVE_TAG(aTags[aPntId]) == FT_Curve_Tag_Conic)
500 {
e4f0cc46 501 isLineSeg = false;
b514beda 502 gp_XY aPntPrev2 = aPntPrev;
503 gp_XY aPntNext2 = aPntNext;
504
505 // previous point is either the real previous point (an "on" point),
506 // or the midpoint between the current one and the previous "conic off" point
507 if (FT_CURVE_TAG(aTags[(aPntId - 1 + aPntsNb) % aPntsNb]) == FT_Curve_Tag_Conic)
508 {
509 aPntPrev2 = (aPntCurr + aPntPrev) * 0.5;
510 }
511
512 // next point is either the real next point or the midpoint
513 if (FT_CURVE_TAG(aTags[(aPntId + 1) % aPntsNb]) == FT_Curve_Tag_Conic)
514 {
515 aPntNext2 = (aPntCurr + aPntNext) * 0.5;
516 }
517
518 my3Poles.SetValue (1, aPntPrev2);
519 my3Poles.SetValue (2, aPntCurr);
520 my3Poles.SetValue (3, aPntNext2);
521 Handle(Geom2d_BezierCurve) aBezierArc = new Geom2d_BezierCurve (my3Poles);
522 if (myIsCompositeCurve)
523 {
524 myConcatMaker.Add (aBezierArc, myPrecision);
525 }
526 else
527 {
528 Handle(Geom_Curve) aCurve3d;
529 if (to3d (aBezierArc, GeomAbs_C1, aCurve3d))
530 {
531 TopoDS_Edge anEdge = BRepLib_MakeEdge (aCurve3d);
532 myBuilder.UpdateEdge (anEdge, aBezierArc, mySurface, aLoc, myPrecision);
533 aWireMaker.Add (anEdge);
534 }
535 }
536 }
537 else if (FT_CURVE_TAG(aTags[aPntId]) == FT_Curve_Tag_Cubic
538 && FT_CURVE_TAG(aTags[(aPntId + 1) % aPntsNb]) == FT_Curve_Tag_Cubic)
539 {
e4f0cc46 540 isLineSeg = false;
b514beda 541 my4Poles.SetValue (1, aPntPrev);
542 my4Poles.SetValue (2, aPntCurr);
543 my4Poles.SetValue (3, aPntNext);
151da08b 544 my4Poles.SetValue (4, gp_Pnt2d(readFTVec (aPntList[(aPntId + 2) % aPntsNb], myScaleUnits, myWidthScaling)));
b514beda 545 Handle(Geom2d_BezierCurve) aBezier = new Geom2d_BezierCurve (my4Poles);
546 if (myIsCompositeCurve)
547 {
548 myConcatMaker.Add (aBezier, myPrecision);
549 }
550 else
551 {
552 Handle(Geom_Curve) aCurve3d;
553 if (to3d (aBezier, GeomAbs_C1, aCurve3d))
554 {
555 TopoDS_Edge anEdge = BRepLib_MakeEdge (aCurve3d);
556 myBuilder.UpdateEdge (anEdge, aBezier, mySurface, aLoc, myPrecision);
557 aWireMaker.Add (anEdge);
558 }
559 }
560 }
561 }
562
563 if (myIsCompositeCurve)
564 {
565 Handle(Geom2d_BSplineCurve) aDraft2d = myConcatMaker.BSplineCurve();
566 if (aDraft2d.IsNull())
567 {
568 continue;
569 }
570
571 const gp_Pnt2d aFirstPnt = aDraft2d->StartPoint();
572 const gp_Pnt2d aLastPnt = aDraft2d->EndPoint();
1bbd7c79 573 if (!myFontParams.IsSingleStrokeFont
e4f0cc46 574 && !aFirstPnt.IsEqual (aLastPnt, myPrecision))
b514beda 575 {
576 Handle(Geom2d_TrimmedCurve) aLine = GCE2d_MakeSegment (aLastPnt, aFirstPnt);
577 myConcatMaker.Add (aLine, myPrecision);
578 }
579
580 Handle(Geom2d_BSplineCurve) aCurve2d = myConcatMaker.BSplineCurve();
581 Handle(Geom_Curve) aCurve3d;
582 if (to3d (aCurve2d, GeomAbs_C0, aCurve3d))
583 {
584 TopoDS_Edge anEdge = BRepLib_MakeEdge (aCurve3d);
585 myBuilder.UpdateEdge (anEdge, aCurve2d, mySurface, aLoc, myPrecision);
586 aWireMaker.Add (anEdge);
587 }
588 myConcatMaker.Clear();
589 }
590 else
591 {
592 if (!aWireMaker.IsDone())
593 {
594 continue;
595 }
596
597 TopoDS_Vertex aFirstV, aLastV;
598 TopExp::Vertices (aWireMaker.Wire(), aFirstV, aLastV);
599 gp_Pnt aFirstPoint = BRep_Tool::Pnt (aFirstV);
600 gp_Pnt aLastPoint = BRep_Tool::Pnt (aLastV);
1bbd7c79 601 if (!myFontParams.IsSingleStrokeFont
e4f0cc46 602 && !aFirstPoint.IsEqual (aLastPoint, myPrecision))
b514beda 603 {
604 aWireMaker.Add (BRepLib_MakeEdge (aFirstV, aLastV));
605 }
606 }
607
608 if (!aWireMaker.IsDone())
609 {
610 continue;
611 }
612
613 TopoDS_Wire aWireDraft = aWireMaker.Wire();
1bbd7c79 614 if (!myFontParams.IsSingleStrokeFont)
e4f0cc46 615 {
3388cf17 616 // collect all wires and set CCW orientation
617 TopoDS_Face aFace;
618 myBuilder.MakeFace (aFace, mySurface, myPrecision);
619 myBuilder.Add (aFace, aWireDraft);
620 BRepTopAdaptor_FClass2d aClass2d (aFace, ::Precision::PConfusion());
621 TopAbs_State aState = aClass2d.PerformInfinitePoint();
622 if (aState != TopAbs_OUT)
e4f0cc46 623 {
3388cf17 624 // need to reverse
625 aWireDraft.Reverse();
e4f0cc46 626 }
3388cf17 627 aWires.Append (aWireDraft);
e4f0cc46 628 }
629 else
630 {
631 if (aFaceCompDraft.IsNull())
632 {
633 myBuilder.MakeCompound (aFaceCompDraft);
634 }
635 myBuilder.Add (aFaceCompDraft, aWireDraft);
636 }
b514beda 637 }
638
3388cf17 639 if (!aWires.IsEmpty())
b514beda 640 {
3388cf17 641 buildFaces (aWires, theShape);
e4f0cc46 642 }
643 else if (!aFaceCompDraft.IsNull())
644 {
645 theShape = aFaceCompDraft;
b514beda 646 }
647
648 myCache.Bind (theChar, theShape);
649 return !theShape.IsNull();
650}