KiCad PCB EDA Suite
Loading...
Searching...
No Matches
outline_decomposer.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KICAD, a free EDA CAD application.
3 *
4 * Copyright (C) 2021 Ola Rinta-Koski <[email protected]>
5 * Copyright (C) 2021-2024 Kicad Developers, see AUTHORS.txt for contributors.
6 *
7 * Outline font class
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, you may find one here:
21 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22 * or you may search the http://www.gnu.org website for the version 2 license,
23 * or you may write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25 */
26
27#include <advanced_config.h>
29#include <bezier_curves.h>
30
31using namespace KIFONT;
32
34 m_outline( aOutline ),
35 m_contours( nullptr )
36{
37}
38
39
40static VECTOR2D toVector2D( const FT_Vector* aFreeTypeVector )
41{
42 return VECTOR2D( (double) aFreeTypeVector->x * GLYPH_SIZE_SCALER,
43 (double) aFreeTypeVector->y * GLYPH_SIZE_SCALER );
44}
45
46
48{
49 CONTOUR contour;
50 contour.m_Orientation = FT_Outline_Get_Orientation( &m_outline );
51 m_contours->push_back( contour );
52}
53
54
56{
57 // don't add repeated points
58 if( m_contours->back().m_Points.empty() || m_contours->back().m_Points.back() != p )
59 m_contours->back().m_Points.push_back( p );
60}
61
62
63int OUTLINE_DECOMPOSER::moveTo( const FT_Vector* aEndPoint, void* aCallbackData )
64{
65 OUTLINE_DECOMPOSER* decomposer = static_cast<OUTLINE_DECOMPOSER*>( aCallbackData );
66
67 decomposer->m_lastEndPoint = toVector2D( aEndPoint );
68
69 decomposer->newContour();
70 decomposer->addContourPoint( decomposer->m_lastEndPoint );
71
72 return 0;
73}
74
75
76int OUTLINE_DECOMPOSER::lineTo( const FT_Vector* aEndPoint, void* aCallbackData )
77{
78 OUTLINE_DECOMPOSER* decomposer = static_cast<OUTLINE_DECOMPOSER*>( aCallbackData );
79
80 decomposer->m_lastEndPoint = toVector2D( aEndPoint );
81
82 decomposer->addContourPoint( decomposer->m_lastEndPoint );
83
84 return 0;
85}
86
87
88int OUTLINE_DECOMPOSER::quadraticTo( const FT_Vector* aControlPoint, const FT_Vector* aEndPoint,
89 void* aCallbackData )
90{
91 return cubicTo( aControlPoint, nullptr, aEndPoint, aCallbackData );
92}
93
94
95int OUTLINE_DECOMPOSER::cubicTo( const FT_Vector* aFirstControlPoint,
96 const FT_Vector* aSecondControlPoint, const FT_Vector* aEndPoint,
97 void* aCallbackData )
98{
99 OUTLINE_DECOMPOSER* decomposer = static_cast<OUTLINE_DECOMPOSER*>( aCallbackData );
100
101 std::vector<VECTOR2D> bezier;
102 bezier.push_back( decomposer->m_lastEndPoint );
103 bezier.push_back( toVector2D( aFirstControlPoint ) );
104
105 if( aSecondControlPoint )
106 {
107 // aSecondControlPoint == nullptr for quadratic Beziers
108 bezier.push_back( toVector2D( aSecondControlPoint ) );
109 }
110
111 bezier.push_back( toVector2D( aEndPoint ) );
112
113 std::vector<VECTOR2D> result;
114 BEZIER_POLY converter( bezier );
115 converter.GetPoly( result, ADVANCED_CFG::GetCfg().m_FontErrorSize );
116
117 for( const VECTOR2D& p : result )
118 decomposer->addContourPoint( p );
119
120 decomposer->m_lastEndPoint = toVector2D( aEndPoint );
121
122 return 0;
123}
124
125
126bool OUTLINE_DECOMPOSER::OutlineToSegments( std::vector<CONTOUR>* aContours )
127{
128 m_contours = aContours;
129
130 FT_Outline_Funcs callbacks;
131
132 callbacks.move_to = moveTo;
133 callbacks.line_to = lineTo;
134 callbacks.conic_to = quadraticTo;
135 callbacks.cubic_to = cubicTo;
136 callbacks.shift = 0;
137 callbacks.delta = 0;
138
139 FT_Error e = FT_Outline_Decompose( &m_outline, &callbacks, this );
140
141 if( e )
142 return false;
143
144 for( CONTOUR& c : *m_contours )
145 c.m_Winding = winding( c.m_Points );
146
147 return true;
148}
149
150
151int OUTLINE_DECOMPOSER::winding( const std::vector<VECTOR2D>& aContour ) const
152{
153 // -1 == counterclockwise, 1 == clockwise
154
155 const int cw = 1;
156 const int ccw = -1;
157
158 if( aContour.size() < 2 )
159 {
160 // zero or one points, so not a clockwise contour - in fact not a contour at all
161 //
162 // It could also be argued that a contour needs 3 extremum points at a minimum to be
163 // considered a proper contour (ie. a glyph (subpart) outline, or a hole)
164 return 0;
165 }
166
167 double sum = 0.0;
168 size_t len = aContour.size();
169
170 for( size_t i = 0; i < len - 1; i++ )
171 {
172 VECTOR2D p1 = aContour[ i ];
173 VECTOR2D p2 = aContour[ i + 1 ];
174
175 sum += ( ( p2.x - p1.x ) * ( p2.y + p1.y ) );
176 }
177
178 sum += ( ( aContour[0].x - aContour[len - 1].x ) * ( aContour[0].y + aContour[len - 1].y ) );
179
180 if( sum > 0.0 )
181 return cw;
182 if( sum < 0.0 )
183 return ccw;
184
185 return 0;
186}
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
Bezier curves to polygon converter.
Definition: bezier_curves.h:38
void GetPoly(std::vector< VECTOR2I > &aOutput, int aMaxError=10)
Convert a Bezier curve to a polygon.
void addContourPoint(const VECTOR2D &p)
OUTLINE_DECOMPOSER(FT_Outline &aOutline)
std::vector< CONTOUR > * m_contours
static int cubicTo(const FT_Vector *aFirstControlPoint, const FT_Vector *aSecondControlPoint, const FT_Vector *aEndPoint, void *aCallbackData)
static int moveTo(const FT_Vector *aEndPoint, void *aCallbackData)
bool OutlineToSegments(std::vector< CONTOUR > *aContours)
static int lineTo(const FT_Vector *aEndPoint, void *aCallbackData)
static int quadraticTo(const FT_Vector *aControlPoint, const FT_Vector *aEndPoint, void *aCallbackData)
int winding(const std::vector< VECTOR2D > &aContour) const
constexpr double GLYPH_SIZE_SCALER
static VECTOR2D toVector2D(const FT_Vector *aFreeTypeVector)
FT_Orientation m_Orientation
VECTOR2< double > VECTOR2D
Definition: vector2d.h:690