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 |
54 | IMPLEMENT_STANDARD_RTTIEXT(StdPrs_BRepFont, Font_FTFont) |
92efcf78 |
55 | |
b514beda |
56 | namespace |
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 |
123 | StdPrs_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 |
137 | void 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 |
149 | StdPrs_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 |
172 | StdPrs_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 |
196 | void StdPrs_BRepFont::Release() |
b514beda |
197 | { |
198 | myCache.Clear(); |
199 | Font_FTFont::Release(); |
200 | } |
201 | |
202 | // ======================================================================= |
203 | // function : SetCompositeCurveMode |
204 | // purpose : |
205 | // ======================================================================= |
7f24b768 |
206 | void 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 |
219 | bool 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 |
236 | bool 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 |
254 | TopoDS_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 |
266 | bool 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 |
286 | Standard_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 |
406 | Standard_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 | } |