2 * Copyright 2012 Google, Inc. All Rights Reserved.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 * Google Author(s): Behdad Esfahbod, Maysum Panju, Wojciech Baranowski
23 // Glyphy is written using C style casts
24 #pragma GCC diagnostic push
25 #pragma GCC diagnostic ignored "-Wold-style-cast"
27 #include "glyphy-common.hh"
28 #include "glyphy-geometry.hh"
29 #include "glyphy-arcs-bezier.hh"
31 using namespace GLyphy::Geometry;
32 using namespace GLyphy::ArcsBezier;
37 * Approximate outlines with multiple arcs
41 struct glyphy_arc_accumulator_t {
42 unsigned int refcount;
46 glyphy_arc_endpoint_accumulator_callback_t callback;
49 glyphy_point_t start_point;
50 glyphy_point_t current_point;
52 unsigned int num_endpoints;
54 glyphy_bool_t success;
58 glyphy_arc_accumulator_t *
59 glyphy_arc_accumulator_create (void)
61 glyphy_arc_accumulator_t *acc = (glyphy_arc_accumulator_t *) calloc (1, sizeof (glyphy_arc_accumulator_t));
64 acc->tolerance = 5e-4;
67 acc->user_data = NULL;
69 glyphy_arc_accumulator_reset (acc);
75 glyphy_arc_accumulator_reset (glyphy_arc_accumulator_t *acc)
77 acc->start_point = acc->current_point = Point (0, 0);
78 acc->need_moveto = true;
79 acc->num_endpoints = 0;
85 glyphy_arc_accumulator_destroy (glyphy_arc_accumulator_t *acc)
87 if (!acc || --acc->refcount)
96 glyphy_arc_accumulator_set_tolerance (glyphy_arc_accumulator_t *acc,
99 acc->tolerance = tolerance;
103 glyphy_arc_accumulator_get_tolerance (glyphy_arc_accumulator_t *acc)
105 return acc->tolerance;
109 glyphy_arc_accumulator_set_callback (glyphy_arc_accumulator_t *acc,
110 glyphy_arc_endpoint_accumulator_callback_t callback,
113 acc->callback = callback;
114 acc->user_data = user_data;
118 glyphy_arc_accumulator_get_callback (glyphy_arc_accumulator_t *acc,
119 glyphy_arc_endpoint_accumulator_callback_t *callback,
122 *callback = acc->callback;
123 *user_data = acc->user_data;
126 /* Accumulation results */
129 glyphy_arc_accumulator_get_error (glyphy_arc_accumulator_t *acc)
131 return acc->max_error;
135 glyphy_arc_accumulator_successful (glyphy_arc_accumulator_t *acc)
144 emit (glyphy_arc_accumulator_t *acc, const Point &p, double d)
146 glyphy_arc_endpoint_t endpoint = {p, d};
147 acc->success = acc->success && acc->callback (&endpoint, acc->user_data);
149 acc->num_endpoints++;
150 acc->current_point = p;
155 accumulate (glyphy_arc_accumulator_t *acc, const Point &p, double d)
157 if (Point (acc->current_point) == p)
159 if (d == GLYPHY_INFINITY) {
160 /* Emit moveto lazily, for cleaner outlines */
161 acc->need_moveto = true;
162 acc->current_point = p;
165 if (acc->need_moveto) {
166 emit (acc, acc->current_point, GLYPHY_INFINITY);
168 acc->start_point = acc->current_point;
169 acc->need_moveto = false;
176 move_to (glyphy_arc_accumulator_t *acc, const Point &p)
178 if (!acc->num_endpoints || p != acc->current_point)
179 accumulate (acc, p, GLYPHY_INFINITY);
183 arc_to (glyphy_arc_accumulator_t *acc, const Point &p1, double d)
185 accumulate (acc, p1, d);
189 bezier (glyphy_arc_accumulator_t *acc, const Bezier &b)
193 std::vector<Arc> arcs;
194 typedef ArcBezierApproximatorQuantizedDefault _ArcBezierApproximator;
195 _ArcBezierApproximator appx (GLYPHY_MAX_D, acc->d_bits);
196 ArcsBezierApproximatorSpringSystem<_ArcBezierApproximator>
197 ::approximate_bezier_with_arcs (b, acc->tolerance, appx, arcs, &e);
199 acc->max_error = std::max (acc->max_error, e);
202 for (unsigned int i = 0; i < arcs.size (); i++)
203 arc_to (acc, arcs[i].p1, arcs[i].d);
207 close_path (glyphy_arc_accumulator_t *acc)
209 if (!acc->need_moveto && Point (acc->current_point) != Point (acc->start_point))
210 arc_to (acc, acc->start_point, 0);
214 glyphy_arc_accumulator_move_to (glyphy_arc_accumulator_t *acc,
215 const glyphy_point_t *p0)
221 glyphy_arc_accumulator_line_to (glyphy_arc_accumulator_t *acc,
222 const glyphy_point_t *p1)
224 arc_to (acc, *p1, 0);
228 glyphy_arc_accumulator_conic_to (glyphy_arc_accumulator_t *acc,
229 const glyphy_point_t *p1,
230 const glyphy_point_t *p2)
232 bezier (acc, Bezier (acc->current_point,
233 Point (acc->current_point).lerp (2/3., *p1),
234 Point (*p2).lerp (2/3., *p1),
239 glyphy_arc_accumulator_cubic_to (glyphy_arc_accumulator_t *acc,
240 const glyphy_point_t *p1,
241 const glyphy_point_t *p2,
242 const glyphy_point_t *p3)
244 bezier (acc, Bezier (acc->current_point, *p1, *p2, *p3));
248 glyphy_arc_accumulator_arc_to (glyphy_arc_accumulator_t *acc,
249 const glyphy_point_t *p1,
252 arc_to (acc, *p1, d);
256 glyphy_arc_accumulator_close_path (glyphy_arc_accumulator_t *acc)
264 * Outline extents from arc list
269 glyphy_arc_list_extents (const glyphy_arc_endpoint_t *endpoints,
270 unsigned int num_endpoints,
271 glyphy_extents_t *extents)
274 glyphy_extents_clear (extents);
275 for (unsigned int i = 0; i < num_endpoints; i++) {
276 const glyphy_arc_endpoint_t &endpoint = endpoints[i];
277 if (endpoint.d == GLYPHY_INFINITY) {
281 Arc arc (p0, endpoint.p, endpoint.d);
284 glyphy_extents_t arc_extents;
285 arc.extents (arc_extents);
286 glyphy_extents_extend (extents, &arc_extents);
290 #pragma GCC diagnostic pop