test_scpr_offset.c (12351B)
1 /* Copyright (C) 2016-2018, 2021-2024 |Méso|Star> (contact@meso-star.com) 2 * 3 * This program is free software: you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published by 5 * the Free Software Foundation, either version 3 of the License, or 6 * (at your option) any later version. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 16 #define _POSIX_C_SOURCE 200112L 17 18 #include "scpr.h" 19 #include "test_scpr_utils.h" 20 21 #include <memory.h> 22 23 static void 24 test_single(void) 25 { 26 const double coords0[] = { 27 0.0, 0.0, 28 0.0, 1.0, 29 1.0, 1.0, 30 1.0, 0.0 31 }; 32 const double coords1[] = { 33 -1.0, -1.0, 34 -1.0, 2.0, 35 2.0, 2.0, 36 2.0, -1.0 37 }; 38 double coords2[] = { 39 0.12345678901234, 0.0, 40 0.0, 1.0, 41 1.0, 1000000000000, /* To be replaced */ 42 1.0, 0.0 43 }; 44 double coords2_reverse[] = { 45 0.12345678901234, 0.0, 46 1.0, 0.0, 47 1.0, 1000000000000, /* To be replaced */ 48 0.0, 1.0 49 }; 50 double** coords; 51 double range[2]; 52 size_t nverts[] = { 4 }; 53 size_t ncomps = 1; 54 struct mem_allocator allocator; 55 struct polygon_context ctx; 56 struct scpr_polygon* polygon; 57 struct scpr_polygon* expected; 58 struct scpr_device_create_args args = SCPR_DEVICE_CREATE_ARGS_DEFAULT; 59 struct scpr_device* dev; 60 int eq; 61 62 mem_init_proxy_allocator(&allocator, &mem_default_allocator); 63 args.allocator = &allocator; 64 OK(scpr_device_create(&args, &dev)); 65 66 /* Set barely in-range value in coords2 */ 67 SCPR(device_get_range(dev, range)); 68 coords2[5] = coords2_reverse[5] = range[1]; 69 70 coords = (double**)MEM_CALLOC(&allocator, ncomps, sizeof(*coords)); 71 *coords = (double*)MEM_CALLOC(&allocator, nverts[0], 2*sizeof(**coords)); 72 memcpy(*coords, coords0, 2*nverts[0]*sizeof(**coords)); 73 74 OK(scpr_polygon_create(dev, &polygon)); 75 OK(scpr_polygon_create(dev, &expected)); 76 77 ctx.coords = coords; 78 ctx.nverts = nverts; 79 ctx.ncomps = ncomps; 80 81 OK(scpr_polygon_setup_indexed_vertices(polygon, ncomps, pget_nverts, pget_pos, &ctx)); 82 OK(scpr_polygon_setup_indexed_vertices(expected, ncomps, pget_nverts, pget_pos, &ctx)); 83 84 /* Offset 0 = unchanged */ 85 OK(scpr_offset_polygon(polygon, 0, SCPR_JOIN_MITER)); 86 OK(scpr_polygon_eq(polygon, expected, &eq)); 87 CHK(eq); 88 CHK(check_stability(dev, polygon)); 89 90 /* Offset 1 */ 91 memcpy(*coords, coords1, 2*nverts[0]*sizeof(**coords)); 92 OK(scpr_polygon_setup_indexed_vertices(expected, ncomps, pget_nverts, pget_pos, &ctx)); 93 94 OK(scpr_offset_polygon(polygon, 1, SCPR_JOIN_MITER)); 95 OK(scpr_polygon_eq(polygon, expected, &eq)); 96 CHK(eq); 97 CHK(check_stability(dev, polygon)); 98 99 /* Offset -1: back to original polygon */ 100 memcpy(*coords, coords0, 2*nverts[0]*sizeof(**coords)); 101 OK(scpr_polygon_setup_indexed_vertices(expected, ncomps, pget_nverts, pget_pos, &ctx)); 102 103 OK(scpr_offset_polygon(polygon, -1, SCPR_JOIN_MITER)); 104 OK(scpr_polygon_eq(polygon, expected, &eq)); 105 CHK(eq); 106 CHK(check_stability(dev, polygon)); 107 108 /* Non representable offset: truncation will ensure stability */ 109 OK(scpr_offset_polygon(polygon, 0.123456789, SCPR_JOIN_MITER)); 110 OK(scpr_offset_polygon(expected, 0.123457, SCPR_JOIN_MITER)); 111 OK(scpr_polygon_eq(polygon, expected, &eq)); 112 CHK(eq); 113 CHK(check_stability(dev, polygon)); 114 115 /* Offset -5: empty polygon */ 116 ncomps = 0; 117 ctx.ncomps = ncomps; 118 OK(scpr_polygon_setup_indexed_vertices(expected, ncomps, pget_nverts, pget_pos, &ctx)); 119 120 OK(scpr_offset_polygon(polygon, -5, SCPR_JOIN_MITER)); 121 OK(scpr_polygon_eq(polygon, expected, &eq)); 122 CHK(eq); 123 CHK(check_stability(dev, polygon)); 124 125 /* Check coordinates barely in-range */ 126 memcpy(*coords, coords2, 2*nverts[0]*sizeof(**coords)); 127 128 ncomps = 1; 129 ctx.ncomps = ncomps; 130 131 OK(scpr_polygon_setup_indexed_vertices(polygon, ncomps, pget_nverts, pget_pos, &ctx)); 132 OK(scpr_polygon_setup_indexed_vertices(expected, ncomps, pget_nverts, pget_pos, &ctx)); 133 134 /* Offset 0 = unchanged */ 135 OK(scpr_offset_polygon(polygon, 0, SCPR_JOIN_MITER)); 136 OK(scpr_polygon_eq(polygon, expected, &eq)); 137 CHK(eq); 138 CHK(check_stability(dev, polygon)); 139 140 /* Check non-effect of CW/CCW */ 141 memcpy(*coords, coords2_reverse, 2*nverts[0]*sizeof(**coords)); 142 OK(scpr_polygon_setup_indexed_vertices(polygon, ncomps, pget_nverts, pget_pos, &ctx)); 143 OK(scpr_offset_polygon(polygon, 0, SCPR_JOIN_MITER)); 144 OK(scpr_polygon_eq(polygon, expected, &eq)); 145 CHK(eq); 146 CHK(check_stability(dev, polygon)); 147 148 /* Check out of range after offset being detected */ 149 BAD(scpr_offset_polygon(polygon, 1, SCPR_JOIN_MITER)); 150 151 /* Cleanup */ 152 OK(scpr_polygon_ref_put(polygon)); 153 OK(scpr_device_ref_put(dev)); 154 OK(scpr_polygon_ref_put(expected)); 155 156 MEM_RM(&allocator, *coords); 157 MEM_RM(&allocator, coords); 158 159 check_memory_allocator(&allocator); 160 mem_shutdown_proxy_allocator(&allocator); 161 CHK(mem_allocated_size() == 0); 162 } 163 164 static void 165 test_double(void) 166 { 167 const double coords0[] = { 168 0.0, 0.0, 169 0.0, 1.0, 170 1.0, 1.0, 171 1.0, 0.0 172 }; 173 const double coords1[] = { 174 10.0, 0.0, 175 10.0, 1.0, 176 11.0, 1.0, 177 11.0, 0.0 178 }; 179 const double coords2[] = { 180 -1.0, -1.0, 181 -1.0, 2.0, 182 2.0, 2.0, 183 2.0, -1.0 184 }; 185 const double coords3[] = { 186 9.0, -1.0, 187 9.0, 2.0, 188 12.0, 2.0, 189 12.0, -1.0 190 }; 191 const double coords4[] = { 192 -4.5, -4.5, 193 -4.5, 5.5, 194 15.5, 5.5, 195 15.5, -4.5 196 }; 197 double** coords; 198 size_t nverts[] = { 4, 4 }; 199 size_t ncomps = 2; 200 struct mem_allocator allocator; 201 struct polygon_context ctx; 202 struct scpr_polygon* polygon; 203 struct scpr_polygon* expected; 204 struct scpr_device_create_args args = SCPR_DEVICE_CREATE_ARGS_DEFAULT; 205 struct scpr_device* dev; 206 int eq; 207 208 mem_init_proxy_allocator(&allocator, &mem_default_allocator); 209 args.allocator = &allocator; 210 OK(scpr_device_create(&args, &dev)); 211 212 coords = (double**)MEM_CALLOC(&allocator, ncomps, sizeof(*coords)); 213 *coords = (double*)MEM_CALLOC(&allocator, nverts[0], 2*sizeof(**coords)); 214 *(coords+1) = (double*)MEM_CALLOC(&allocator, nverts[1], 2*sizeof(**coords)); 215 memcpy(*coords, coords0, 2*nverts[0]*sizeof(**coords)); 216 memcpy(*(coords+1), coords1, 2*nverts[1]*sizeof(**coords)); 217 218 OK(scpr_polygon_create(dev, &polygon)); 219 OK(scpr_polygon_create(dev, &expected)); 220 221 ctx.coords = coords; 222 ctx.nverts = nverts; 223 ctx.ncomps = ncomps; 224 225 OK(scpr_polygon_setup_indexed_vertices(polygon, ncomps, pget_nverts, pget_pos, &ctx)); 226 OK(scpr_polygon_setup_indexed_vertices(expected, ncomps, pget_nverts, pget_pos, &ctx)); 227 228 /* Offset 0 = unchanged */ 229 OK(scpr_offset_polygon(polygon, 0, SCPR_JOIN_MITER)); 230 OK(scpr_polygon_eq(polygon, expected, &eq)); 231 CHK(eq); 232 233 /* Offset 1 */ 234 memcpy(*coords, coords2, 2*nverts[0]*sizeof(**coords)); 235 memcpy(*(coords+1), coords3, 2*nverts[1]*sizeof(**coords)); 236 OK(scpr_polygon_setup_indexed_vertices(expected, ncomps, pget_nverts, pget_pos, &ctx)); 237 238 OK(scpr_offset_polygon(polygon, 1, SCPR_JOIN_MITER)); 239 OK(scpr_polygon_eq(polygon, expected, &eq)); 240 CHK(eq); 241 242 /* Offset -1: back to original polygon */ 243 memcpy(*coords, coords0, 2*nverts[0]*sizeof(**coords)); 244 memcpy(*(coords+1), coords1, 2*nverts[1]*sizeof(**coords)); 245 OK(scpr_polygon_setup_indexed_vertices(expected, ncomps, pget_nverts, pget_pos, &ctx)); 246 247 OK(scpr_offset_polygon(polygon, -1, SCPR_JOIN_MITER)); 248 OK(scpr_polygon_eq(polygon, expected, &eq)); 249 CHK(eq); 250 251 /* Offset 4.5: the 2 squares merge */ 252 ncomps = 1; 253 ctx.ncomps = ncomps; 254 memcpy(*coords, coords4, 2*nverts[0]*sizeof(**coords)); 255 OK(scpr_polygon_setup_indexed_vertices(expected, ncomps, pget_nverts, pget_pos, &ctx)); 256 257 OK(scpr_offset_polygon(polygon, 4.5, SCPR_JOIN_MITER)); 258 OK(scpr_polygon_eq(polygon, expected, &eq)); 259 CHK(eq); 260 261 /* Offset -5: empty polygon */ 262 ncomps = 0; 263 ctx.ncomps = ncomps; 264 OK(scpr_polygon_setup_indexed_vertices(expected, ncomps, pget_nverts, pget_pos, &ctx)); 265 266 OK(scpr_offset_polygon(polygon, -5, SCPR_JOIN_MITER)); 267 OK(scpr_polygon_eq(polygon, expected, &eq)); 268 CHK(eq); 269 270 OK(scpr_polygon_ref_put(polygon)); 271 OK(scpr_device_ref_put(dev)); 272 OK(scpr_polygon_ref_put(expected)); 273 274 MEM_RM(&allocator, *coords); 275 MEM_RM(&allocator, *(coords+1)); 276 MEM_RM(&allocator, coords); 277 278 check_memory_allocator(&allocator); 279 mem_shutdown_proxy_allocator(&allocator); 280 CHK(mem_allocated_size() == 0); 281 } 282 283 static void 284 test_internal(void) 285 { 286 const double coords0[] = { 287 -10, -10, 288 -10, 10, 289 10, 10, 290 10, -10 291 }; 292 const double coords1[] = { 293 -5, -5, 294 5, -5, 295 5, 5, 296 -5, 5 297 }; 298 const double coords2[] = { 299 -9, -9, 300 -9, 9, 301 9, 9, 302 9, -9 303 }; 304 const double coords3[] = { 305 -6, -6, 306 6, -6, 307 6, 6, 308 -6, 6 309 }; 310 const double coords4[] = { 311 -15, -15, 312 -15, 15, 313 15, 15, 314 15, -15 315 }; 316 double** coords; 317 size_t nverts[] = { 4, 4 }; 318 size_t ncomps = 2; 319 struct mem_allocator allocator; 320 struct polygon_context ctx; 321 struct scpr_polygon* polygon; 322 struct scpr_polygon* expected; 323 struct scpr_device_create_args args = SCPR_DEVICE_CREATE_ARGS_DEFAULT; 324 struct scpr_device* dev; 325 int eq; 326 327 mem_init_proxy_allocator(&allocator, &mem_default_allocator); 328 args.allocator = &allocator; 329 OK(scpr_device_create(&args, &dev)); 330 331 coords = (double**)MEM_CALLOC(&allocator, ncomps, sizeof(*coords)); 332 *coords = (double*)MEM_CALLOC(&allocator, nverts[0], 2*sizeof(**coords)); 333 *(coords+1) = (double*)MEM_CALLOC(&allocator, nverts[1], 2*sizeof(**coords)); 334 memcpy(*coords, coords0, 2*nverts[0]*sizeof(**coords)); 335 memcpy(*(coords+1), coords1, 2*nverts[1]*sizeof(**coords)); 336 337 OK(scpr_polygon_create(dev, &polygon)); 338 OK(scpr_polygon_create(dev, &expected)); 339 340 ctx.coords = coords; 341 ctx.nverts = nverts; 342 ctx.ncomps = ncomps; 343 344 OK(scpr_polygon_setup_indexed_vertices(polygon, ncomps, pget_nverts, pget_pos, &ctx)); 345 OK(scpr_polygon_setup_indexed_vertices(expected, ncomps, pget_nverts, pget_pos, &ctx)); 346 347 /* Offset 0 = unchanged */ 348 OK(scpr_offset_polygon(polygon, 0, SCPR_JOIN_MITER)); 349 OK(scpr_polygon_eq(polygon, expected, &eq)); 350 CHK(eq); 351 352 /* Offset -1 */ 353 memcpy(*coords, coords3, 2*nverts[0]*sizeof(**coords)); 354 memcpy(*(coords+1), coords2, 2*nverts[1]*sizeof(**coords)); 355 OK(scpr_polygon_setup_indexed_vertices(expected, ncomps, pget_nverts, pget_pos, &ctx)); 356 357 OK(scpr_offset_polygon(polygon, -1, SCPR_JOIN_MITER)); 358 OK(scpr_polygon_eq(polygon, expected, &eq)); 359 CHK(eq); 360 361 /* Offset 1: back to original polygon */ 362 memcpy(*coords, coords0, 2*nverts[0]*sizeof(**coords)); 363 memcpy(*(coords+1), coords1, 2*nverts[1]*sizeof(**coords)); 364 OK(scpr_polygon_setup_indexed_vertices(expected, ncomps, pget_nverts, pget_pos, &ctx)); 365 366 OK(scpr_offset_polygon(polygon, 1, SCPR_JOIN_MITER)); 367 OK(scpr_polygon_eq(polygon, expected, &eq)); 368 CHK(eq); 369 370 /* Offset 5: internal path disappears */ 371 ncomps = 1; 372 ctx.ncomps = ncomps; 373 memcpy(*coords, coords4, 2*nverts[0]*sizeof(**coords)); 374 OK(scpr_polygon_setup_indexed_vertices(expected, ncomps, pget_nverts, pget_pos, &ctx)); 375 376 OK(scpr_offset_polygon(polygon, 5, SCPR_JOIN_MITER)); 377 OK(scpr_polygon_eq(polygon, expected, &eq)); 378 CHK(eq); 379 380 /* From the original polygon, offset -2.5: empty polygon */ 381 ncomps = 2; 382 ctx.ncomps = ncomps; 383 memcpy(*coords, coords0, 2*nverts[0]*sizeof(**coords)); 384 memcpy(*(coords+1), coords1, 2*nverts[1]*sizeof(**coords)); 385 OK(scpr_polygon_setup_indexed_vertices(polygon, ncomps, pget_nverts, pget_pos, &ctx)); 386 387 ncomps = 0; 388 ctx.ncomps = ncomps; 389 OK(scpr_polygon_setup_indexed_vertices(expected, ncomps, pget_nverts, pget_pos, &ctx)); 390 391 OK(scpr_offset_polygon(polygon, -2.5, SCPR_JOIN_MITER)); 392 OK(scpr_polygon_eq(polygon, expected, &eq)); 393 CHK(eq); 394 395 OK(scpr_polygon_ref_put(polygon)); 396 OK(scpr_polygon_ref_put(expected)); 397 OK(scpr_device_ref_put(dev)); 398 399 MEM_RM(&allocator, *coords); 400 MEM_RM(&allocator, *(coords+1)); 401 MEM_RM(&allocator, coords); 402 403 check_memory_allocator(&allocator); 404 mem_shutdown_proxy_allocator(&allocator); 405 CHK(mem_allocated_size() == 0); 406 } 407 408 int 409 main(int argc, char** argv) 410 { 411 (void)argc; (void)argv; 412 test_single(); 413 test_double(); 414 test_internal(); 415 return 0; 416 }