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 | */ |
77 | graphene_point_t * |
78 | graphene_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 | */ |
91 | void |
92 | graphene_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 | */ |
111 | graphene_point_t * |
112 | graphene_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 | */ |
133 | graphene_point_t * |
134 | graphene_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 | */ |
153 | graphene_point_t * |
154 | graphene_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 | |
163 | static bool |
164 | point_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 | */ |
189 | bool |
190 | graphene_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 | */ |
209 | float |
210 | graphene_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 | */ |
244 | bool |
245 | graphene_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 | */ |
273 | void |
274 | graphene_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 | */ |
293 | void |
294 | graphene_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 | |
300 | static 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 | */ |
311 | const graphene_point_t * |
312 | graphene_point_zero (void) |
313 | { |
314 | return &_graphene_point_zero; |
315 | } |
316 | |