1/* graphene-point.c: Point
2 *
3 * SPDX-License-Identifier: MIT
4 *
5 * Copyright 2014 Emmanuele Bassi
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25
26/**
27 * SECTION:graphene-point
28 * @Title: Point
29 * @short_description: A point with 2 coordinates
30 *
31 * #graphene_point_t is a data structure capable of describing a point with
32 * two coordinates:
33 *
34 * * @graphene_point_t.x
35 * * @graphene_point_t.y
36 */
37
38#include "graphene-private.h"
39
40#include "graphene-point.h"
41
42#include "graphene-simd4f.h"
43#include "graphene-vec2.h"
44
45#include <math.h>
46
47/**
48 * graphene_point_alloc: (constructor)
49 *
50 * Allocates a new #graphene_point_t structure.
51 *
52 * The coordinates of the returned point are (0, 0).
53 *
54 * It's possible to chain this function with graphene_point_init()
55 * or graphene_point_init_from_point(), e.g.:
56 *
57 * |[<!-- language="C" -->
58 * graphene_point_t *
59 * point_new (float x, float y)
60 * {
61 * return graphene_point_init (graphene_point_alloc (), x, y);
62 * }
63 *
64 * graphene_point_t *
65 * point_copy (const graphene_point_t *p)
66 * {
67 * return graphene_point_init_from_point (graphene_point_alloc (), p);
68 * }
69 * ]|
70 *
71 * Returns: (transfer full): the newly allocated #graphene_point_t.
72 * Use graphene_point_free() to free the resources allocated by
73 * this function.
74 *
75 * Since: 1.0
76 */
77graphene_point_t *
78graphene_point_alloc (void)
79{
80 return calloc (nmemb: 1, size: sizeof (graphene_point_t));
81}
82
83/**
84 * graphene_point_free:
85 * @p: a #graphene_point_t
86 *
87 * Frees the resources allocated by graphene_point_alloc().
88 *
89 * Since: 1.0
90 */
91void
92graphene_point_free (graphene_point_t *p)
93{
94 free (ptr: p);
95}
96
97/**
98 * graphene_point_init:
99 * @p: a #graphene_point_t
100 * @x: the X coordinate
101 * @y: the Y coordinate
102 *
103 * Initializes @p to the given @x and @y coordinates.
104 *
105 * It's safe to call this function multiple times.
106 *
107 * Returns: (transfer none): the initialized point
108 *
109 * Since: 1.0
110 */
111graphene_point_t *
112graphene_point_init (graphene_point_t *p,
113 float x,
114 float y)
115{
116 p->x = x;
117 p->y = y;
118
119 return p;
120}
121
122/**
123 * graphene_point_init_from_point:
124 * @p: a #graphene_point_t
125 * @src: the #graphene_point_t to use
126 *
127 * Initializes @p with the same coordinates of @src.
128 *
129 * Returns: (transfer none): the initialized point
130 *
131 * Since: 1.0
132 */
133graphene_point_t *
134graphene_point_init_from_point (graphene_point_t *p,
135 const graphene_point_t *src)
136{
137 *p = *src;
138
139 return p;
140}
141
142/**
143 * graphene_point_init_from_vec2:
144 * @p: the #graphene_point_t to initialize
145 * @src: a #graphene_vec2_t
146 *
147 * Initializes @p with the coordinates inside the given #graphene_vec2_t.
148 *
149 * Returns: (transfer none): the initialized point
150 *
151 * Since: 1.4
152 */
153graphene_point_t *
154graphene_point_init_from_vec2 (graphene_point_t *p,
155 const graphene_vec2_t *src)
156{
157 p->x = graphene_simd4f_get_x (src->value);
158 p->y = graphene_simd4f_get_y (src->value);
159
160 return p;
161}
162
163static bool
164point_equal (const void *p1,
165 const void *p2)
166{
167 const graphene_point_t *a = p1;
168 const graphene_point_t *b = p2;
169
170 return graphene_point_near (a, b, GRAPHENE_FLOAT_EPSILON);
171}
172
173/**
174 * graphene_point_equal:
175 * @a: a #graphene_point_t
176 * @b: a #graphene_point_t
177 *
178 * Checks if the two points @a and @b point to the same
179 * coordinates.
180 *
181 * This function accounts for floating point fluctuations; if
182 * you want to control the fuzziness of the match, you can use
183 * graphene_point_near() instead.
184 *
185 * Returns: `true` if the points have the same coordinates
186 *
187 * Since: 1.0
188 */
189bool
190graphene_point_equal (const graphene_point_t *a,
191 const graphene_point_t *b)
192{
193 return graphene_pointer_equal (p1: a, p2: b, func: point_equal);
194}
195
196/**
197 * graphene_point_distance:
198 * @a: a #graphene_point_t
199 * @b: a #graphene_point_t
200 * @d_x: (out) (optional): distance component on the X axis
201 * @d_y: (out) (optional): distance component on the Y axis
202 *
203 * Computes the distance between @a and @b.
204 *
205 * Returns: the distance between the two points
206 *
207 * Since: 1.0
208 */
209float
210graphene_point_distance (const graphene_point_t *a,
211 const graphene_point_t *b,
212 float *d_x,
213 float *d_y)
214{
215 if (a == b)
216 return 0.f;
217
218 graphene_simd4f_t v_a = graphene_simd4f_init (a->x, a->y, 0.f, 0.f);
219 graphene_simd4f_t v_b = graphene_simd4f_init (b->x, b->y, 0.f, 0.f);
220 graphene_simd4f_t v_res = graphene_simd4f_sub (v_a, v_b);
221
222 if (d_x != NULL)
223 *d_x = fabsf (graphene_simd4f_get_x (v_res));
224
225 if (d_y != NULL)
226 *d_y = fabsf (graphene_simd4f_get_y (v_res));
227
228 return graphene_simd4f_get_x (graphene_simd4f_length2 (v_res));
229}
230
231/**
232 * graphene_point_near:
233 * @a: a #graphene_point_t
234 * @b: a #graphene_point_t
235 * @epsilon: threshold between the two points
236 *
237 * Checks whether the two points @a and @b are within
238 * the threshold of @epsilon.
239 *
240 * Returns: `true` if the distance is within @epsilon
241 *
242 * Since: 1.0
243 */
244bool
245graphene_point_near (const graphene_point_t *a,
246 const graphene_point_t *b,
247 float epsilon)
248{
249 if (a == b)
250 return true;
251
252 graphene_simd4f_t v_a = graphene_simd4f_init (a->x, a->y, 0.f, 0.f);
253 graphene_simd4f_t v_b = graphene_simd4f_init (b->x, b->y, 0.f, 0.f);
254 graphene_simd4f_t v_res = graphene_simd4f_sub (v_a, v_b);
255
256 return fabsf (graphene_simd4f_get_x (v_res)) < epsilon &&
257 fabsf (graphene_simd4f_get_y (v_res)) < epsilon;
258}
259
260/**
261 * graphene_point_interpolate:
262 * @a: a #graphene_point_t
263 * @b: a #graphene_point_t
264 * @factor: the linear interpolation factor
265 * @res: (out caller-allocates): return location for the interpolated
266 * point
267 *
268 * Linearly interpolates the coordinates of @a and @b using the
269 * given @factor.
270 *
271 * Since: 1.0
272 */
273void
274graphene_point_interpolate (const graphene_point_t *a,
275 const graphene_point_t *b,
276 double factor,
277 graphene_point_t *res)
278{
279 res->x = graphene_lerp (a: a->x, b: b->x, factor);
280 res->y = graphene_lerp (a: a->y, b: b->y, factor);
281}
282
283/**
284 * graphene_point_to_vec2:
285 * @p: a #graphene_point_t
286 * @v: (out caller-allocates): return location for the vertex
287 *
288 * Stores the coordinates of the given #graphene_point_t into a
289 * #graphene_vec2_t.
290 *
291 * Since: 1.4
292 */
293void
294graphene_point_to_vec2 (const graphene_point_t *p,
295 graphene_vec2_t *v)
296{
297 v->value = graphene_simd4f_init (p->x, p->y, 0.f, 0.f);
298}
299
300static const graphene_point_t _graphene_point_zero;
301
302/**
303 * graphene_point_zero:
304 *
305 * Returns a point fixed at (0, 0).
306 *
307 * Returns: (transfer none): a fixed point
308 *
309 * Since: 1.0
310 */
311const graphene_point_t *
312graphene_point_zero (void)
313{
314 return &_graphene_point_zero;
315}
316

source code of gtk/subprojects/graphene/src/graphene-point.c