commit 9ac6cd51cc6862b8637755ff787eace8938bcf54
parent bf5ee0c1fce474a78500db63aca3cfd7ea08f83c
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Thu, 29 Sep 2022 16:34:20 +0200
Merge branch 'feature-offset' into develop
Diffstat:
10 files changed, 697 insertions(+), 224 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -51,15 +51,17 @@ set(VERSION_MINOR 1)
set(VERSION_PATCH 3)
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
-set(SCPR_FILES_SRC scpr_mesh.c)
-set(SCPR_FILES_INC scpr.h)
+set(SCPR_FILES_SRC scpr_mesh.c scpr_polygon.c)
+set(SCPR_FILES_INC_API scpr.h)
+set(SCPR_FILES_INC scpr_c.h)
set(SCPR_FILES_DOC COPYING README.md)
rcmake_prepend_path(SCPR_FILES_SRC ${SCPR_SOURCE_DIR})
rcmake_prepend_path(SCPR_FILES_INC ${SCPR_SOURCE_DIR})
+rcmake_prepend_path(SCPR_FILES_INC_API ${SCPR_SOURCE_DIR})
rcmake_prepend_path(SCPR_FILES_DOC ${PROJECT_SOURCE_DIR}/../)
set_source_files_properties(${SCPR_FILES_SRC} PROPERTIES LANGUAGE CXX)
-add_library(scpr SHARED ${SCPR_FILES_SRC} ${SCPR_FILES_INC})
+add_library(scpr SHARED ${SCPR_FILES_SRC} ${SCPR_FILES_INC} ${SCPR_FILES_INC_API})
set_target_properties(scpr PROPERTIES
DEFINE_SYMBOL SCPR_SHARED_BUILD
VERSION ${VERSION}
@@ -87,7 +89,9 @@ if(NOT NO_TEST)
add_test(${_name} ${_name})
endfunction()
new_test(test_scpr_clip)
+ new_test(test_scpr_offset)
new_test(test_scpr_mesh)
+ new_test(test_scpr_polygon)
rcmake_copy_runtime_libraries(test_scpr_clip)
endif()
@@ -99,6 +103,6 @@ install(TARGETS scpr
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin)
-install(FILES ${SCPR_FILES_INC} DESTINATION include/star/)
+install(FILES ${SCPR_FILES_INC_API} DESTINATION include/star/)
install(FILES ${SCPR_FILES_DOC} DESTINATION share/doc/star-cpr/)
diff --git a/src/scpr.h b/src/scpr.h
@@ -41,25 +41,61 @@ enum scpr_operation {
SCPR_OPERATIONS_COUNT__
};
-/* Public polygon data type. Define the list of the countour vertices. */
-struct scpr_polygon {
- void (*get_position)(const size_t ivert, double pos[2], void* ctx);
- size_t nvertices; /* #vertices */
- /* User data provided as the last argument of the get_position functor */
- void* context;
+enum scpr_join_type {
+ SCPR_JOIN_SQUARE,
+ SCPR_JOIN_ROUND,
+ SCPR_JOIN_MITER,
+ SCPR_JOIN_TYPES_COUNT__
};
-#define SCPR_POLYGON_NULL__ { NULL, 0, NULL }
-static const struct scpr_polygon SCPR_POLYGON_NULL = SCPR_POLYGON_NULL__;
/* Forward declaration */
struct mem_allocator;
+/* Opaque 2D closed polygon data type */
+struct scpr_polygon;
/* Opaque 2D mesh data type */
struct scpr_mesh;
BEGIN_DECLS
SCPR_API res_T
+scpr_polygon_create
+ (struct mem_allocator* allocator, /* May be NULL <=> Use default allocator */
+ struct scpr_polygon** polygon);
+
+SCPR_API res_T
+scpr_polygon_ref_get
+ (struct scpr_polygon* polygon);
+
+SCPR_API res_T
+scpr_polygon_ref_put
+ (struct scpr_polygon* polygon);
+
+SCPR_API res_T
+scpr_polygon_setup_indexed_vertices
+ (struct scpr_polygon* polygon,
+ const size_t nverts, /* #vertices */
+ void (*get_position)(const size_t ivert, double pos[2], void* ctx),
+ void* data); /* Client data set as the last param of the callbacks */
+
+SCPR_API res_T
+scpr_offset_polygon
+ (struct scpr_polygon* polygon,
+ const double offset, /* Can be either positive or negative */
+ const enum scpr_join_type join_type);
+
+SCPR_API res_T
+scpr_polygon_get_vertices_count
+ (const struct scpr_polygon* polygon,
+ size_t* nverts);
+
+SCPR_API res_T
+scpr_polygon_get_position
+ (const struct scpr_polygon* polygon,
+ const size_t ivert,
+ double position[2]);
+
+SCPR_API res_T
scpr_mesh_create
(struct mem_allocator* allocator, /* May be NULL <=> Use default allocator */
struct scpr_mesh** mesh);
diff --git a/src/scpr_c.h b/src/scpr_c.h
@@ -0,0 +1,61 @@
+/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef SCPR_C_H__
+#define SCPR_C_H__
+
+#include "scpr.h"
+
+#include <rsys/rsys.h>
+#include <rsys/ref_count.h>
+#include <rsys/double2.h>
+#include <rsys/dynamic_array_double.h>
+#include <rsys/dynamic_array_size_t.h>
+#include <rsys/hash_table.h>
+
+#undef PI
+#include <clipper.core.h>
+
+struct mem_allocator;
+
+struct vertex { double pos[2]; };
+static FINLINE int
+vertex_eq(const struct vertex* a, const struct vertex* b)
+{ return d2_eq(a->pos, b->pos); }
+
+/* Define the vertex to index hash table */
+#define HTABLE_NAME vertex
+#define HTABLE_DATA size_t
+#define HTABLE_KEY struct vertex
+#define HTABLE_KEY_FUNCTOR_EQ vertex_eq
+#include <rsys/hash_table.h>
+
+struct scpr_polygon {
+ Clipper2Lib::PathsD path;
+ double lower[2], upper[2]; /* Polygon AABB */
+
+ ref_T ref;
+ struct mem_allocator* allocator;
+};
+
+struct scpr_mesh {
+ struct darray_double coords;
+ struct darray_size_t indices;
+
+ ref_T ref;
+ struct mem_allocator* allocator;
+};
+
+#endif
diff --git a/src/scpr_mesh.c b/src/scpr_mesh.c
@@ -14,44 +14,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "scpr.h"
+#include "scpr_c.h"
-#include <clipper.core.h>
-#include <clipper.engine.h>
-#include <rsys/double2.h>
-#include <rsys/dynamic_array_double.h>
-#include <rsys/dynamic_array_size_t.h>
-#include <rsys/hash_table.h>
#include <rsys/mem_allocator.h>
-#include <rsys/ref_count.h>
#include <polygon.h>
+#undef PI
#include <clipper.h>
-struct vertex { double pos[2]; };
-static FINLINE int
-vertex_eq(const struct vertex* a, const struct vertex* b)
-{ return d2_eq(a->pos, b->pos); }
-
-/* Define the vertex to index hash table */
-#define HTABLE_NAME vertex
-#define HTABLE_DATA size_t
-#define HTABLE_KEY struct vertex
-#define HTABLE_KEY_FUNCTOR_EQ vertex_eq
-#include <rsys/hash_table.h>
-
-struct poly {
- struct darray_double coords;
- double lower[2], upper[2]; /* Polygon AABB */
-};
-
-struct scpr_mesh {
- struct darray_double coords;
- struct darray_size_t indices;
-
- ref_T ref;
- struct mem_allocator* allocator;
-};
-
/*******************************************************************************
* Helper functions
******************************************************************************/
@@ -88,53 +58,6 @@ aabb_is_degenerated(const double lower[2], const double upper[2])
return lower[0] >= upper[0] || lower[1] >= upper[1];
}
-static INLINE void
-poly_init(struct mem_allocator* allocator, struct poly* poly)
-{
- ASSERT(allocator && poly);
- darray_double_init(allocator, &poly->coords);
-}
-
-static INLINE void
-poly_release(struct poly* poly)
-{
- ASSERT(poly);
- darray_double_release(&poly->coords);
-}
-
-static res_T
-poly_setup(struct poly* poly, const struct scpr_polygon* desc)
-{
- size_t ivert;
- res_T res = RES_OK;
- ASSERT(poly && desc);
-
- if(!desc->get_position && !desc->nvertices) {
- res = RES_BAD_ARG;
- goto error;
- }
-
- res = darray_double_resize(&poly->coords, desc->nvertices * 2/*#coords*/);
- if(res != RES_OK) goto error;
-
- d2_splat(poly->lower, DBL_MAX);
- d2_splat(poly->upper,-DBL_MAX);
- FOR_EACH(ivert, 0, desc->nvertices) {
- double* pos = darray_double_data_get(&poly->coords) + ivert*2;
- desc->get_position(ivert, pos, desc->context);
- d2_min(poly->lower, poly->lower, pos);
- d2_max(poly->upper, poly->upper, pos);
- }
-
-exit:
- return res;
-error:
- darray_double_clear(&poly->coords);
- d2_splat(poly->lower, DBL_MAX);
- d2_splat(poly->upper,-DBL_MAX);
- goto exit;
-}
-
static void
triangle_compute_aabb
(double tri[3][2],
@@ -466,7 +389,6 @@ scpr_mesh_clip
struct scpr_polygon* poly_desc)
{
double lower[2], upper[2];
- struct poly poly;
struct polygon* polygon = NULL; /* Use to triangulate clipped polygons */
struct darray_double coords; /* Coordinates of the clipped mesh */
struct darray_size_t indices; /* Indices of the clipped mesh */
@@ -475,10 +397,8 @@ scpr_mesh_clip
Clipper2Lib::PathsD output; /* Contour of the clipped polgyon */
Clipper2Lib::PathsD cand_path; /* Contour of the candidate polygon */
Clipper2Lib::PathD tmp;
- Clipper2Lib::PathsD clip_path; /* Contour of the clip polygon */
Clipper2Lib::ClipType clip_type; /* Type of clipping to perform */
- size_t ivert, nverts;
- size_t itri, ntris;
+ size_t itri, ntris, ivert;
res_T res = RES_OK;
@@ -491,29 +411,14 @@ scpr_mesh_clip
darray_size_t_init(mesh->allocator, &indices);
htable_vertex_init(mesh->allocator, &vertices);
- poly_init(mesh->allocator, &poly);
- res = poly_setup(&poly, poly_desc);
- if(res != RES_OK) goto error;
- if(aabb_is_degenerated(poly.lower, poly.upper)) goto exit;
+ if(aabb_is_degenerated(poly_desc->lower, poly_desc->upper)) goto exit;
mesh_compute_aabb(mesh, lower, upper);
if(aabb_is_degenerated(lower, upper)) goto exit;
/* Compute the overall aabb of the candidate and the clip polygon */
- d2_min(lower, lower, poly.lower);
- d2_max(upper, upper, poly.upper);
-
- /* Setup the clip path */
- nverts = darray_double_size_get(&poly.coords) / 2/*#coords per vertex*/;
- tmp.clear();
- FOR_EACH(ivert, 0, nverts) {
- const double* v = darray_double_cdata_get(&poly.coords) + ivert*2;
- Clipper2Lib::PointD pt;
- pt.x = v[0];
- pt.y = v[1];
- tmp.push_back(pt);
- }
- clip_path.push_back(tmp);
+ d2_min(lower, lower, poly_desc->lower);
+ d2_max(upper, upper, poly_desc->upper);
/* Create the polygon structure used to triangulate the clipped polygons */
res = polygon_create(mesh->allocator, &polygon);
@@ -532,8 +437,8 @@ scpr_mesh_clip
SCPR(mesh_get_position(mesh, ids[2], tri[2]));
triangle_compute_aabb(tri, lower, upper);
- /* Do not clip triangles that don not intersect the clip AABB */
- if(!aabb_intersect(lower, upper, poly.lower, poly.upper)) {
+ /* Do not clip triangles that do not intersect the clip AABB */
+ if(!aabb_intersect(lower, upper, poly_desc->lower, poly_desc->upper)) {
if(op != SCPR_AND) {
res = register_triangle(tri, &coords, &indices, &vertices);
if(res != RES_OK) goto error;
@@ -555,7 +460,7 @@ scpr_mesh_clip
/* Clip the polygon */
clipper.Clear();
clipper.AddSubject(cand_path);
- clipper.AddClip(clip_path);
+ clipper.AddClip(poly_desc->path);
clipper.Execute(clip_type, Clipper2Lib::FillRule::EvenOdd, output);
/* Register the resulting clipped polygons */
@@ -573,7 +478,6 @@ exit:
darray_double_release(&coords);
darray_size_t_release(&indices);
htable_vertex_release(&vertices);
- poly_release(&poly);
return res;
error:
goto exit;
diff --git a/src/scpr_polygon.c b/src/scpr_polygon.c
@@ -0,0 +1,258 @@
+/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "scpr.h"
+#include "scpr_c.h"
+
+#include <new>
+#include <rsys/mem_allocator.h>
+#include <rsys/rsys.h>
+
+#undef PI
+#include <clipper.h>
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static FINLINE Clipper2Lib::JoinType
+scpr_join_type_to_clipper_join_type(const enum scpr_join_type t)
+{
+ Clipper2Lib::JoinType jtype;
+ switch(t) {
+ case SCPR_JOIN_SQUARE: jtype = Clipper2Lib::JoinType::Square; break;
+ case SCPR_JOIN_ROUND: jtype = Clipper2Lib::JoinType::Round; break;
+ case SCPR_JOIN_MITER: jtype = Clipper2Lib::JoinType::Miter; break;
+ default: FATAL("Unreachable code\n"); break;
+ }
+ return jtype;
+}
+
+static void
+polygon_release(ref_T* ref)
+{
+ struct scpr_polygon* polygon;
+ ASSERT(ref);
+ polygon = CONTAINER_OF(ref, struct scpr_polygon, ref);
+ polygon->path.clear();
+ MEM_RM(polygon->allocator, polygon);
+}
+
+/*******************************************************************************
+ * Exported functions
+ ******************************************************************************/
+res_T
+scpr_polygon_create
+ (struct mem_allocator* mem_allocator,
+ struct scpr_polygon** out_polygon)
+{
+ struct scpr_polygon* polygon = NULL;
+ struct mem_allocator* allocator = NULL;
+ res_T res = RES_OK;
+
+ if(!out_polygon) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ allocator = mem_allocator ? mem_allocator : &mem_default_allocator;
+ polygon = (struct scpr_polygon*)
+ MEM_CALLOC(allocator, 1, sizeof(struct scpr_polygon));
+ if(!polygon) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+ ref_init(&polygon->ref);
+ polygon->allocator = allocator;
+
+exit:
+ if(out_polygon) *out_polygon = polygon;
+ return res;
+
+error:
+ if(polygon) {
+ SCPR(polygon_ref_put(polygon));
+ polygon = NULL;
+ }
+ goto exit;
+}
+
+res_T
+scpr_polygon_ref_get
+ (struct scpr_polygon* polygon)
+{
+ if(!polygon) return RES_BAD_ARG;
+ ref_get(&polygon->ref);
+ return RES_OK;
+}
+
+res_T
+scpr_polygon_ref_put
+ (struct scpr_polygon* polygon)
+{
+ if(!polygon) return RES_BAD_ARG;
+ ref_put(&polygon->ref, polygon_release);
+ return RES_OK;
+}
+
+res_T
+scpr_polygon_setup_indexed_vertices
+ (struct scpr_polygon* polygon,
+ const size_t nverts,
+ void (*get_position)(const size_t ivert, double pos[2], void* ctx),
+ void* data)
+{
+ size_t i;
+ Clipper2Lib::PathD path;
+ res_T res = RES_OK;
+
+ if(!polygon || !nverts || !get_position || !data) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ try {
+ path.reserve(nverts);
+ }
+ catch(std::bad_alloc &e) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+ catch(...) {
+ res = RES_UNKNOWN_ERR;
+ goto error;
+ }
+
+ d2_splat(polygon->lower, DBL_MAX);
+ d2_splat(polygon->upper,-DBL_MAX);
+
+ /* Fetch polygon positions */
+ FOR_EACH(i, 0, nverts) {
+ double tmp[2];
+ Clipper2Lib::PointD pt;
+ get_position(i, tmp, data);
+ pt.x = tmp[0];
+ pt.y = tmp[1];
+ path.push_back(pt);
+
+ d2_min(polygon->lower, polygon->lower, tmp);
+ d2_max(polygon->upper, polygon->upper, tmp);
+ }
+
+ try {
+ polygon->path.push_back(path);
+ }
+ catch(std::bad_alloc &e) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+ catch(...) {
+ res = RES_UNKNOWN_ERR;
+ goto error;
+ }
+
+exit:
+ return res;
+error:
+ if(polygon) {
+ polygon->path.clear();
+ d2_splat(polygon->lower, DBL_MAX);
+ d2_splat(polygon->upper,-DBL_MAX);
+ }
+ goto exit;
+}
+
+res_T
+scpr_polygon_get_vertices_count
+ (const struct scpr_polygon* polygon,
+ size_t* nverts)
+{
+ if(!polygon || !nverts) return RES_BAD_ARG;
+ ASSERT(polygon->path.size() <= 1);
+ if(polygon->path.size() < 1) {
+ *nverts = 0;
+ } else {
+ *nverts = polygon->path[0].size();
+ }
+ return RES_OK;
+}
+
+res_T
+scpr_polygon_get_position
+ (const struct scpr_polygon* polygon,
+ const size_t ivert,
+ double pos[2])
+{
+ size_t nverts;
+ const size_t i = ivert;
+ const Clipper2Lib::PointD* pt;
+ if(!polygon || !pos) return RES_BAD_ARG;
+ SCPR(polygon_get_vertices_count(polygon, &nverts));
+ if(ivert >= nverts) return RES_BAD_ARG;
+ pt = &polygon->path[0][i];
+ pos[0] = pt->x;
+ pos[1] = pt->y;
+ return RES_OK;
+}
+
+res_T
+scpr_offset_polygon
+ (struct scpr_polygon* poly_desc,
+ const double offset, /* Can be either positive or negative */
+ const enum scpr_join_type join_type)
+{
+ size_t i, nverts;
+ Clipper2Lib::PathD tmp;
+ Clipper2Lib::PathsD polygon;
+ Clipper2Lib::JoinType cjt;
+ res_T res = RES_OK;
+
+ if(!poly_desc) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ switch(join_type) {
+ case SCPR_JOIN_SQUARE:
+ case SCPR_JOIN_ROUND:
+ case SCPR_JOIN_MITER:
+ break;
+ default:
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ cjt = scpr_join_type_to_clipper_join_type(join_type);
+ poly_desc->path = Clipper2Lib::InflatePaths(poly_desc->path, offset, cjt,
+ Clipper2Lib::EndType::Polygon);
+
+ /* Rebuild AABB */
+ res = scpr_polygon_get_vertices_count(poly_desc, &nverts);
+ if(res != RES_OK) goto error;
+
+ if(nverts > 0) {
+ d2_splat(poly_desc->lower, DBL_MAX);
+ d2_splat(poly_desc->upper,-DBL_MAX);
+ FOR_EACH(i, 0, nverts) {
+ double pos[2];
+ res = scpr_polygon_get_position(poly_desc, i, pos);
+ if(res != RES_OK) goto error;
+ d2_min(poly_desc->lower, poly_desc->lower, pos);
+ d2_max(poly_desc->upper, poly_desc->upper, pos);
+ }
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
diff --git a/src/test_scpr_clip.c b/src/test_scpr_clip.c
@@ -20,16 +20,6 @@
#include <rsys/stretchy_array.h>
static void
-get_clip_pos(const size_t ivert, double pos[2], void* ctx)
-{
- const double* coords = ctx;
- CHK(pos != NULL);
- CHK(ctx != NULL);
- pos[0] = coords[ivert*2+0];
- pos[1] = coords[ivert*2+1];
-}
-
-static void
dump_obj(FILE* stream, const struct scpr_mesh* mesh)
{
size_t i, n;
@@ -56,74 +46,93 @@ dump_obj(FILE* stream, const struct scpr_mesh* mesh)
}
static void
-test_triangle(struct scpr_mesh* mesh)
+test_triangle
+ (struct mem_allocator* allocator,
+ struct scpr_mesh* mesh)
{
const double triangle_pos[] = { 0.0, 0.0, 0.0, 1.0, 1.0, 0.0 };
const size_t triangle_ids[] = { 0, 1, 2 };
const double clip_pos[] = { -1.0, 0.25, 1.0, 0.75, 1, 0.25 };
- struct scpr_polygon poly;
- struct mesh_context ctx;
+ struct scpr_polygon* poly;
+ struct polygon_context pctx;
+ struct mesh_context mctx;
size_t ntris;
- ctx.coords = triangle_pos;
- ctx.nverts = 3;
- ctx.indices = triangle_ids;
- ctx.ntris = 1;
+ pctx.coords = clip_pos;
+ pctx.nverts = sizeof(clip_pos)/(2*sizeof(double));
+ CHK(scpr_polygon_create(allocator, &poly) == RES_OK);
+ CHK(scpr_polygon_setup_indexed_vertices(poly, pctx.nverts, pget_pos, &pctx)
+ == RES_OK);
+
+ mctx.coords = triangle_pos;
+ mctx.nverts = 3;
+ mctx.indices = triangle_ids;
+ mctx.ntris = 1;
CHK(scpr_mesh_setup_indexed_vertices
- (mesh, ctx.ntris, get_ids, 3, get_pos, &ctx) == RES_OK);
+ (mesh, mctx.ntris, mget_ids, 3, mget_pos, &mctx) == RES_OK);
- poly.get_position = get_clip_pos;
- poly.nvertices = sizeof(clip_pos)/(2*sizeof(double));
- poly.context = (void*)clip_pos;
CHK(scpr_mesh_clip(NULL, SCPR_OPERATIONS_COUNT__, NULL) == RES_BAD_ARG);
CHK(scpr_mesh_clip(mesh, SCPR_OPERATIONS_COUNT__, NULL) == RES_BAD_ARG);
- CHK(scpr_mesh_clip(NULL, SCPR_OPERATIONS_COUNT__, &poly) == RES_BAD_ARG);
- CHK(scpr_mesh_clip(mesh, SCPR_OPERATIONS_COUNT__, &poly) == RES_BAD_ARG);
+ CHK(scpr_mesh_clip(NULL, SCPR_OPERATIONS_COUNT__, poly) == RES_BAD_ARG);
+ CHK(scpr_mesh_clip(mesh, SCPR_OPERATIONS_COUNT__, poly) == RES_BAD_ARG);
CHK(scpr_mesh_clip(NULL, SCPR_SUB, NULL) == RES_BAD_ARG);
CHK(scpr_mesh_clip(mesh, SCPR_SUB, NULL) == RES_BAD_ARG);
- CHK(scpr_mesh_clip(NULL, SCPR_SUB, &poly) == RES_BAD_ARG);
- CHK(scpr_mesh_clip(mesh, SCPR_SUB, &poly) == RES_OK);
+ CHK(scpr_mesh_clip(NULL, SCPR_SUB, poly) == RES_BAD_ARG);
+ CHK(scpr_mesh_clip(mesh, SCPR_SUB, poly) == RES_OK);
/*dump_obj(stdout, mesh);*/
CHK(scpr_mesh_get_triangles_count(mesh, &ntris) == RES_OK);
CHK(ntris == 3);
+
+ CHK(scpr_polygon_ref_put(poly) == RES_OK);
}
static void
-test_quad(struct scpr_mesh* mesh)
+test_quad
+ (struct mem_allocator* allocator,
+ struct scpr_mesh* mesh)
{
const double quad_pos[] = { 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0 };
const size_t quad_ids[] = { 0, 1, 3, 3, 1, 2 };
const double clip_pos[] = { -0.25, 0.25, -0.25, 0.75, 1.25, 0.75, 1.25, 0.25 };
- struct scpr_polygon poly;
- struct mesh_context ctx;
-
- ctx.coords = quad_pos;
- ctx.nverts = sizeof(quad_pos)/(2*sizeof(double));
- ctx.indices = quad_ids;
- ctx.ntris = sizeof(quad_ids)/(3*sizeof(size_t));
+ struct scpr_polygon* poly;
+ struct polygon_context pctx;
+ struct mesh_context mctx;
+
+ pctx.coords = clip_pos;
+ pctx.nverts = sizeof(clip_pos)/(2*sizeof(double));
+ CHK(scpr_polygon_create(allocator, &poly) == RES_OK);
+ CHK(scpr_polygon_setup_indexed_vertices(poly, pctx.nverts, pget_pos, &pctx)
+ == RES_OK);
+
+ mctx.coords = quad_pos;
+ mctx.nverts = sizeof(quad_pos)/(2*sizeof(double));
+ mctx.indices = quad_ids;
+ mctx.ntris = sizeof(quad_ids)/(3*sizeof(size_t));
CHK(scpr_mesh_setup_indexed_vertices
- (mesh, ctx.ntris, get_ids, ctx.nverts, get_pos, &ctx) == RES_OK);
+ (mesh, mctx.ntris, mget_ids, mctx.nverts, mget_pos, &mctx) == RES_OK);
- poly.get_position = get_clip_pos;
- poly.nvertices = sizeof(clip_pos)/(2*sizeof(double));
- poly.context = (void*)clip_pos;
- CHK(scpr_mesh_clip(mesh, SCPR_AND, &poly) == RES_OK);
+ CHK(scpr_mesh_clip(mesh, SCPR_AND, poly) == RES_OK);
/*dump_obj(stdout, mesh);*/
+
+ CHK(scpr_polygon_ref_put(poly) == RES_OK);
}
static void
-test_disk(struct scpr_mesh* mesh)
+test_disk
+ (struct mem_allocator* allocator,
+ struct scpr_mesh* mesh)
{
const double clip[] = { -1.75, -1.75, 1.75, -1.75, 1.75, 1.75, -1.75, 1.75 };
const size_t ninternal_disks = 10;
const double radius = 2.5;
const double internal_disk_step = radius / (double)ninternal_disks;
const size_t nslices = 64;
- struct mesh_context ctx;
- struct scpr_polygon poly;
+ struct scpr_polygon* poly;
+ struct polygon_context pctx;
+ struct mesh_context mctx;
double* pos = NULL;
size_t* ids = NULL;
size_t i, j;
@@ -172,22 +181,26 @@ test_disk(struct scpr_mesh* mesh)
sa_push(ids, id1);
}
- ctx.coords = pos;
- ctx.nverts = sa_size(pos)/2;
- ctx.indices = ids;
- ctx.ntris = sa_size(ids)/3;
+ pctx.coords = clip;
+ pctx.nverts = sizeof(clip)/(2*sizeof(double));
+ CHK(scpr_polygon_create(allocator, &poly) == RES_OK);
+ CHK(scpr_polygon_setup_indexed_vertices(poly, pctx.nverts, pget_pos, &pctx)
+ == RES_OK);
+
+ mctx.coords = pos;
+ mctx.nverts = sa_size(pos)/2;
+ mctx.indices = ids;
+ mctx.ntris = sa_size(ids)/3;
CHK(scpr_mesh_setup_indexed_vertices
- (mesh, ctx.ntris, get_ids, ctx.nverts, get_pos, &ctx) == RES_OK);
+ (mesh, mctx.ntris, mget_ids, mctx.nverts, mget_pos, &mctx) == RES_OK);
- poly.get_position = get_clip_pos;
- poly.nvertices = sizeof(clip)/(2*sizeof(double));
- poly.context = (void*)clip;
- CHK(scpr_mesh_clip(mesh, SCPR_SUB, &poly) == RES_OK);
+ CHK(scpr_mesh_clip(mesh, SCPR_SUB, poly) == RES_OK);
dump_obj(stdout, mesh);
sa_release(pos);
sa_release(ids);
+ CHK(scpr_polygon_ref_put(poly) == RES_OK);
}
int
@@ -201,9 +214,9 @@ main(int argc, char** argv)
CHK(scpr_mesh_create(&allocator, &mesh) == RES_OK);
- test_triangle(mesh);
- test_quad(mesh);
- test_disk(mesh);
+ test_triangle(&allocator, mesh);
+ test_quad(&allocator, mesh);
+ test_disk(&allocator, mesh);
CHK(scpr_mesh_ref_put(mesh) == RES_OK);
diff --git a/src/test_scpr_mesh.c b/src/test_scpr_mesh.c
@@ -75,68 +75,68 @@ main(int argc, char** argv)
CHK(SETUP(mesh, 0, NULL, 0, NULL, NULL) == RES_BAD_ARG);
CHK(SETUP(NULL, ntris, NULL, 0, NULL, NULL) == RES_BAD_ARG);
CHK(SETUP(mesh, ntris, NULL, 0, NULL, NULL) == RES_BAD_ARG);
- CHK(SETUP(NULL, 0, get_ids, 0, NULL, NULL) == RES_BAD_ARG);
- CHK(SETUP(mesh, 0, get_ids, 0, NULL, NULL) == RES_BAD_ARG);
- CHK(SETUP(NULL, ntris, get_ids, 0, NULL, NULL) == RES_BAD_ARG);
- CHK(SETUP(mesh, ntris, get_ids, 0, NULL, NULL) == RES_BAD_ARG);
+ CHK(SETUP(NULL, 0, mget_ids, 0, NULL, NULL) == RES_BAD_ARG);
+ CHK(SETUP(mesh, 0, mget_ids, 0, NULL, NULL) == RES_BAD_ARG);
+ CHK(SETUP(NULL, ntris, mget_ids, 0, NULL, NULL) == RES_BAD_ARG);
+ CHK(SETUP(mesh, ntris, mget_ids, 0, NULL, NULL) == RES_BAD_ARG);
CHK(SETUP(NULL, 0, NULL, nverts, NULL, NULL) == RES_BAD_ARG);
CHK(SETUP(mesh, 0, NULL, nverts, NULL, NULL) == RES_BAD_ARG);
CHK(SETUP(NULL, ntris, NULL, nverts, NULL, NULL) == RES_BAD_ARG);
CHK(SETUP(mesh, ntris, NULL, nverts, NULL, NULL) == RES_BAD_ARG);
- CHK(SETUP(NULL, 0, get_ids, nverts, NULL, NULL) == RES_BAD_ARG);
- CHK(SETUP(mesh, 0, get_ids, nverts, NULL, NULL) == RES_BAD_ARG);
- CHK(SETUP(NULL, ntris, get_ids, nverts, NULL, NULL) == RES_BAD_ARG);
- CHK(SETUP(mesh, ntris, get_ids, nverts, NULL, NULL) == RES_BAD_ARG);
- CHK(SETUP(NULL, 0, NULL, 0, get_pos, NULL) == RES_BAD_ARG);
- CHK(SETUP(mesh, 0, NULL, 0, get_pos, NULL) == RES_BAD_ARG);
- CHK(SETUP(NULL, ntris, NULL, 0, get_pos, NULL) == RES_BAD_ARG);
- CHK(SETUP(mesh, ntris, NULL, 0, get_pos, NULL) == RES_BAD_ARG);
- CHK(SETUP(NULL, 0, get_ids, 0, get_pos, NULL) == RES_BAD_ARG);
- CHK(SETUP(mesh, 0, get_ids, 0, get_pos, NULL) == RES_BAD_ARG);
- CHK(SETUP(NULL, ntris, get_ids, 0, get_pos, NULL) == RES_BAD_ARG);
- CHK(SETUP(mesh, ntris, get_ids, 0, get_pos, NULL) == RES_BAD_ARG);
- CHK(SETUP(NULL, 0, NULL, nverts, get_pos, NULL) == RES_BAD_ARG);
- CHK(SETUP(mesh, 0, NULL, nverts, get_pos, NULL) == RES_BAD_ARG);
- CHK(SETUP(NULL, ntris, NULL, nverts, get_pos, NULL) == RES_BAD_ARG);
- CHK(SETUP(mesh, ntris, NULL, nverts, get_pos, NULL) == RES_BAD_ARG);
- CHK(SETUP(NULL, 0, get_ids, nverts, get_pos, NULL) == RES_BAD_ARG);
- CHK(SETUP(mesh, 0, get_ids, nverts, get_pos, NULL) == RES_BAD_ARG);
- CHK(SETUP(NULL, ntris, get_ids, nverts, get_pos, NULL) == RES_BAD_ARG);
- CHK(SETUP(mesh, ntris, get_ids, nverts, get_pos, NULL) == RES_BAD_ARG);
+ CHK(SETUP(NULL, 0, mget_ids, nverts, NULL, NULL) == RES_BAD_ARG);
+ CHK(SETUP(mesh, 0, mget_ids, nverts, NULL, NULL) == RES_BAD_ARG);
+ CHK(SETUP(NULL, ntris, mget_ids, nverts, NULL, NULL) == RES_BAD_ARG);
+ CHK(SETUP(mesh, ntris, mget_ids, nverts, NULL, NULL) == RES_BAD_ARG);
+ CHK(SETUP(NULL, 0, NULL, 0, mget_pos, NULL) == RES_BAD_ARG);
+ CHK(SETUP(mesh, 0, NULL, 0, mget_pos, NULL) == RES_BAD_ARG);
+ CHK(SETUP(NULL, ntris, NULL, 0, mget_pos, NULL) == RES_BAD_ARG);
+ CHK(SETUP(mesh, ntris, NULL, 0, mget_pos, NULL) == RES_BAD_ARG);
+ CHK(SETUP(NULL, 0, mget_ids, 0, mget_pos, NULL) == RES_BAD_ARG);
+ CHK(SETUP(mesh, 0, mget_ids, 0, mget_pos, NULL) == RES_BAD_ARG);
+ CHK(SETUP(NULL, ntris, mget_ids, 0, mget_pos, NULL) == RES_BAD_ARG);
+ CHK(SETUP(mesh, ntris, mget_ids, 0, mget_pos, NULL) == RES_BAD_ARG);
+ CHK(SETUP(NULL, 0, NULL, nverts, mget_pos, NULL) == RES_BAD_ARG);
+ CHK(SETUP(mesh, 0, NULL, nverts, mget_pos, NULL) == RES_BAD_ARG);
+ CHK(SETUP(NULL, ntris, NULL, nverts, mget_pos, NULL) == RES_BAD_ARG);
+ CHK(SETUP(mesh, ntris, NULL, nverts, mget_pos, NULL) == RES_BAD_ARG);
+ CHK(SETUP(NULL, 0, mget_ids, nverts, mget_pos, NULL) == RES_BAD_ARG);
+ CHK(SETUP(mesh, 0, mget_ids, nverts, mget_pos, NULL) == RES_BAD_ARG);
+ CHK(SETUP(NULL, ntris, mget_ids, nverts, mget_pos, NULL) == RES_BAD_ARG);
+ CHK(SETUP(mesh, ntris, mget_ids, nverts, mget_pos, NULL) == RES_BAD_ARG);
CHK(SETUP(NULL, 0, NULL, 0, NULL, &ctx) == RES_BAD_ARG);
CHK(SETUP(mesh, 0, NULL, 0, NULL, &ctx) == RES_BAD_ARG);
CHK(SETUP(NULL, ntris, NULL, 0, NULL, &ctx) == RES_BAD_ARG);
CHK(SETUP(mesh, ntris, NULL, 0, NULL, &ctx) == RES_BAD_ARG);
- CHK(SETUP(NULL, 0, get_ids, 0, NULL, &ctx) == RES_BAD_ARG);
- CHK(SETUP(mesh, 0, get_ids, 0, NULL, &ctx) == RES_BAD_ARG);
- CHK(SETUP(NULL, ntris, get_ids, 0, NULL, &ctx) == RES_BAD_ARG);
- CHK(SETUP(mesh, ntris, get_ids, 0, NULL, &ctx) == RES_BAD_ARG);
+ CHK(SETUP(NULL, 0, mget_ids, 0, NULL, &ctx) == RES_BAD_ARG);
+ CHK(SETUP(mesh, 0, mget_ids, 0, NULL, &ctx) == RES_BAD_ARG);
+ CHK(SETUP(NULL, ntris, mget_ids, 0, NULL, &ctx) == RES_BAD_ARG);
+ CHK(SETUP(mesh, ntris, mget_ids, 0, NULL, &ctx) == RES_BAD_ARG);
CHK(SETUP(NULL, 0, NULL, nverts, NULL, &ctx) == RES_BAD_ARG);
CHK(SETUP(mesh, 0, NULL, nverts, NULL, &ctx) == RES_BAD_ARG);
CHK(SETUP(NULL, ntris, NULL, nverts, NULL, &ctx) == RES_BAD_ARG);
CHK(SETUP(mesh, ntris, NULL, nverts, NULL, &ctx) == RES_BAD_ARG);
- CHK(SETUP(NULL, 0, get_ids, nverts, NULL, &ctx) == RES_BAD_ARG);
- CHK(SETUP(mesh, 0, get_ids, nverts, NULL, &ctx) == RES_BAD_ARG);
- CHK(SETUP(NULL, ntris, get_ids, nverts, NULL, &ctx) == RES_BAD_ARG);
- CHK(SETUP(mesh, ntris, get_ids, nverts, NULL, &ctx) == RES_BAD_ARG);
- CHK(SETUP(NULL, 0, NULL, 0, get_pos, &ctx) == RES_BAD_ARG);
- CHK(SETUP(mesh, 0, NULL, 0, get_pos, &ctx) == RES_BAD_ARG);
- CHK(SETUP(NULL, ntris, NULL, 0, get_pos, &ctx) == RES_BAD_ARG);
- CHK(SETUP(mesh, ntris, NULL, 0, get_pos, &ctx) == RES_BAD_ARG);
- CHK(SETUP(NULL, 0, get_ids, 0, get_pos, &ctx) == RES_BAD_ARG);
- CHK(SETUP(mesh, 0, get_ids, 0, get_pos, &ctx) == RES_BAD_ARG);
- CHK(SETUP(NULL, ntris, get_ids, 0, get_pos, &ctx) == RES_BAD_ARG);
- CHK(SETUP(mesh, ntris, get_ids, 0, get_pos, &ctx) == RES_BAD_ARG);
- CHK(SETUP(NULL, 0, NULL, nverts, get_pos, &ctx) == RES_BAD_ARG);
- CHK(SETUP(mesh, 0, NULL, nverts, get_pos, &ctx) == RES_BAD_ARG);
- CHK(SETUP(NULL, ntris, NULL, nverts, get_pos, &ctx) == RES_BAD_ARG);
- CHK(SETUP(mesh, ntris, NULL, nverts, get_pos, &ctx) == RES_BAD_ARG);
- CHK(SETUP(NULL, 0, get_ids, nverts, get_pos, &ctx) == RES_BAD_ARG);
- CHK(SETUP(mesh, 0, get_ids, nverts, get_pos, &ctx) == RES_BAD_ARG);
- CHK(SETUP(NULL, ntris, get_ids, nverts, get_pos, &ctx) == RES_BAD_ARG);
- CHK(SETUP(mesh, ntris, get_ids, nverts, get_pos, &ctx) == RES_OK);
+ CHK(SETUP(NULL, 0, mget_ids, nverts, NULL, &ctx) == RES_BAD_ARG);
+ CHK(SETUP(mesh, 0, mget_ids, nverts, NULL, &ctx) == RES_BAD_ARG);
+ CHK(SETUP(NULL, ntris, mget_ids, nverts, NULL, &ctx) == RES_BAD_ARG);
+ CHK(SETUP(mesh, ntris, mget_ids, nverts, NULL, &ctx) == RES_BAD_ARG);
+ CHK(SETUP(NULL, 0, NULL, 0, mget_pos, &ctx) == RES_BAD_ARG);
+ CHK(SETUP(mesh, 0, NULL, 0, mget_pos, &ctx) == RES_BAD_ARG);
+ CHK(SETUP(NULL, ntris, NULL, 0, mget_pos, &ctx) == RES_BAD_ARG);
+ CHK(SETUP(mesh, ntris, NULL, 0, mget_pos, &ctx) == RES_BAD_ARG);
+ CHK(SETUP(NULL, 0, mget_ids, 0, mget_pos, &ctx) == RES_BAD_ARG);
+ CHK(SETUP(mesh, 0, mget_ids, 0, mget_pos, &ctx) == RES_BAD_ARG);
+ CHK(SETUP(NULL, ntris, mget_ids, 0, mget_pos, &ctx) == RES_BAD_ARG);
+ CHK(SETUP(mesh, ntris, mget_ids, 0, mget_pos, &ctx) == RES_BAD_ARG);
+ CHK(SETUP(NULL, 0, NULL, nverts, mget_pos, &ctx) == RES_BAD_ARG);
+ CHK(SETUP(mesh, 0, NULL, nverts, mget_pos, &ctx) == RES_BAD_ARG);
+ CHK(SETUP(NULL, ntris, NULL, nverts, mget_pos, &ctx) == RES_BAD_ARG);
+ CHK(SETUP(mesh, ntris, NULL, nverts, mget_pos, &ctx) == RES_BAD_ARG);
+ CHK(SETUP(NULL, 0, mget_ids, nverts, mget_pos, &ctx) == RES_BAD_ARG);
+ CHK(SETUP(mesh, 0, mget_ids, nverts, mget_pos, &ctx) == RES_BAD_ARG);
+ CHK(SETUP(NULL, ntris, mget_ids, nverts, mget_pos, &ctx) == RES_BAD_ARG);
+ CHK(SETUP(mesh, ntris, mget_ids, nverts, mget_pos, &ctx) == RES_OK);
ctx.indices = indices_bad;
- CHK(SETUP(mesh, 1, get_ids, nverts, get_pos, &ctx) == RES_BAD_ARG);
+ CHK(SETUP(mesh, 1, mget_ids, nverts, mget_pos, &ctx) == RES_BAD_ARG);
#undef SETUP
CHK(scpr_mesh_get_triangles_count(NULL, NULL) == RES_BAD_ARG);
@@ -153,7 +153,7 @@ main(int argc, char** argv)
ctx.indices = indices;
CHK(scpr_mesh_setup_indexed_vertices
- (mesh, ntris, get_ids, nverts, get_pos, &ctx) == RES_OK);
+ (mesh, ntris, mget_ids, nverts, mget_pos, &ctx) == RES_OK);
CHK(scpr_mesh_get_triangles_count(mesh, &n) == RES_OK);
CHK(n == ntris);
CHK(scpr_mesh_get_vertices_count(mesh, &n) == RES_OK);
diff --git a/src/test_scpr_offset.c b/src/test_scpr_offset.c
@@ -0,0 +1,69 @@
+/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "scpr.h"
+#include "test_scpr_utils.h"
+
+int
+main(int argc, char** argv)
+{
+ const double coords[] = {
+ 0.0, 0.0,
+ 0.0, 1.0,
+ 1.0, 1.0,
+ 1.0, 0.0
+ };
+ const size_t nverts = sizeof(coords)/(2*sizeof(double));
+ double pos[2];
+ size_t i;
+ struct mem_allocator allocator;
+ struct polygon_context ctx;
+ struct scpr_polygon* polygon;
+ (void)argc, (void)argv;
+
+ mem_init_proxy_allocator(&allocator, &mem_default_allocator);
+
+ CHK(scpr_polygon_create(&allocator, &polygon) == RES_OK);
+
+ ctx.coords = coords;
+ ctx.nverts = nverts;
+
+
+ CHK(scpr_polygon_setup_indexed_vertices(polygon, nverts, pget_pos, &ctx)
+ == RES_OK);
+
+ CHK(scpr_offset_polygon(polygon, 0, SCPR_JOIN_MITER) == RES_OK);
+ for(i = 0; i < nverts; i++) {
+ CHK(scpr_polygon_get_position(polygon, i, pos) == RES_OK);
+ CHK(coords[2*i+0] == pos[0] && coords[2*i+1] == pos[1]);
+ }
+
+ CHK(scpr_offset_polygon(polygon, 1, SCPR_JOIN_MITER) == RES_OK);
+ for(i = 0; i < nverts; i++) {
+ double expected[2];
+ CHK(scpr_polygon_get_position(polygon, i, pos) == RES_OK);
+ expected[0] = coords[2*i+0] != 0 ? 2 : -1;
+ expected[1] = coords[2*i+1] != 0 ? 2 : -1;
+ CHK(expected[0] == pos[0] && expected[1] == pos[1]);
+ }
+
+ CHK(scpr_polygon_ref_put(polygon) == RES_OK);
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHK(mem_allocated_size() == 0);
+ return 0;
+}
+
diff --git a/src/test_scpr_polygon.c b/src/test_scpr_polygon.c
@@ -0,0 +1,111 @@
+/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "scpr.h"
+#include "test_scpr_utils.h"
+
+int
+main(int argc, char** argv)
+{
+ const double coords[] = {
+ 0.0, 0.0,
+ 0.0, 0.5,
+ 0.0, 1.0,
+ 0.5, 0.0,
+ 0.5, 0.5,
+ 0.5, 1.0,
+ 1.0, 0.0,
+ 1.0, 0.5,
+ 1.0, 1.0
+ };
+ const size_t nverts = sizeof(coords)/(2*sizeof(double));
+ double pos[2];
+ size_t i, n;
+ struct mem_allocator allocator;
+ struct polygon_context ctx;
+ struct scpr_polygon* polygon;
+ (void)argc, (void)argv;
+
+ mem_init_proxy_allocator(&allocator, &mem_default_allocator);
+
+ CHK(scpr_polygon_create(NULL, NULL) == RES_BAD_ARG);
+ CHK(scpr_polygon_create(&allocator, NULL) == RES_BAD_ARG);
+ CHK(scpr_polygon_create(NULL, &polygon) == RES_OK);
+
+ CHK(scpr_polygon_ref_get(NULL) == RES_BAD_ARG);
+ CHK(scpr_polygon_ref_get(polygon) == RES_OK);
+ CHK(scpr_polygon_ref_put(NULL) == RES_BAD_ARG);
+ CHK(scpr_polygon_ref_put(polygon) == RES_OK);
+ CHK(scpr_polygon_ref_put(polygon) == RES_OK);
+
+ CHK(scpr_polygon_create(&allocator, &polygon) == RES_OK);
+
+ CHK(scpr_polygon_get_vertices_count(polygon, &n) == RES_OK);
+ CHK(n == 0);
+
+ ctx.coords = coords;
+ ctx.nverts = nverts;
+
+ #define SETUP scpr_polygon_setup_indexed_vertices
+ CHK(SETUP(NULL, 0, NULL, NULL) == RES_BAD_ARG);
+ CHK(SETUP(polygon, 0, NULL, NULL) == RES_BAD_ARG);
+ CHK(SETUP(NULL, nverts, NULL, NULL) == RES_BAD_ARG);
+ CHK(SETUP(polygon, nverts, NULL, NULL) == RES_BAD_ARG);
+ CHK(SETUP(NULL, 0, pget_pos, NULL) == RES_BAD_ARG);
+ CHK(SETUP(polygon, 0, pget_pos, NULL) == RES_BAD_ARG);
+ CHK(SETUP(NULL, nverts, pget_pos, NULL) == RES_BAD_ARG);
+ CHK(SETUP(polygon, nverts, pget_pos, NULL) == RES_BAD_ARG);
+ CHK(SETUP(NULL, 0, NULL, &ctx) == RES_BAD_ARG);
+ CHK(SETUP(polygon, 0, NULL, &ctx) == RES_BAD_ARG);
+ CHK(SETUP(NULL, nverts, NULL, &ctx) == RES_BAD_ARG);
+ CHK(SETUP(polygon, nverts, NULL, &ctx) == RES_BAD_ARG);
+ CHK(SETUP(NULL, 0, pget_pos, &ctx) == RES_BAD_ARG);
+ CHK(SETUP(polygon, 0, pget_pos, &ctx) == RES_BAD_ARG);
+ CHK(SETUP(NULL, nverts, pget_pos, &ctx) == RES_BAD_ARG);
+ CHK(SETUP(polygon, nverts, pget_pos, &ctx) == RES_OK);
+ #undef SETUP
+
+ CHK(scpr_polygon_get_vertices_count(NULL, NULL) == RES_BAD_ARG);
+ CHK(scpr_polygon_get_vertices_count(polygon, NULL) == RES_BAD_ARG);
+ CHK(scpr_polygon_get_vertices_count(NULL, &n) == RES_BAD_ARG);
+ CHK(scpr_polygon_get_vertices_count(polygon, &n) == RES_OK);
+ CHK(n == nverts);
+
+ CHK(scpr_polygon_get_position(NULL, nverts, NULL) == RES_BAD_ARG);
+ CHK(scpr_polygon_get_position(polygon, nverts, NULL) == RES_BAD_ARG);
+ CHK(scpr_polygon_get_position(NULL, 0, NULL) == RES_BAD_ARG);
+ CHK(scpr_polygon_get_position(polygon, 0, NULL) == RES_BAD_ARG);
+ CHK(scpr_polygon_get_position(NULL, nverts, pos) == RES_BAD_ARG);
+ CHK(scpr_polygon_get_position(polygon, nverts, pos) == RES_BAD_ARG);
+ CHK(scpr_polygon_get_position(NULL, 0, pos) == RES_BAD_ARG);
+ FOR_EACH(i, 0, nverts) {
+ CHK(scpr_polygon_get_position(polygon, i, pos) == RES_OK);
+ CHK(pos[0] == coords[i*2+0]);
+ CHK(pos[1] == coords[i*2+1]);
+ }
+
+ CHK(scpr_offset_polygon(NULL, 0, SCPR_JOIN_TYPES_COUNT__) == RES_BAD_ARG);
+ CHK(scpr_offset_polygon(polygon, 0, SCPR_JOIN_TYPES_COUNT__) == RES_BAD_ARG);
+ CHK(scpr_offset_polygon(NULL, 0, SCPR_JOIN_MITER) == RES_BAD_ARG);
+ CHK(scpr_offset_polygon(polygon, 0, SCPR_JOIN_MITER) == RES_OK);
+
+ CHK(scpr_polygon_ref_put(polygon) == RES_OK);
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHK(mem_allocated_size() == 0);
+ return 0;
+}
+
diff --git a/src/test_scpr_utils.h b/src/test_scpr_utils.h
@@ -19,6 +19,23 @@
#include <rsys/mem_allocator.h>
#include <stdio.h>
+struct polygon_context {
+ const double* coords;
+ size_t nverts;
+};
+
+static INLINE void
+pget_pos(const size_t ivert, double pos[2], void* context)
+{
+ const struct polygon_context* ctx = context;
+ CHK(pos != NULL);
+ CHK(context != NULL);
+ CHK(ctx->coords != NULL);
+ CHK(ivert < ctx->nverts);
+ pos[0] = ctx->coords[ivert*2 + 0];
+ pos[1] = ctx->coords[ivert*2 + 1];
+}
+
struct mesh_context {
const double* coords;
size_t nverts;
@@ -26,8 +43,8 @@ struct mesh_context {
size_t ntris;
};
-static void
-get_pos(const size_t ivert, double pos[2], void* context)
+static INLINE void
+mget_pos(const size_t ivert, double pos[2], void* context)
{
const struct mesh_context* ctx = context;
CHK(pos != NULL);
@@ -38,8 +55,8 @@ get_pos(const size_t ivert, double pos[2], void* context)
pos[1] = ctx->coords[ivert*2 + 1];
}
-static void
-get_ids(const size_t itri, size_t ids[3], void* context)
+static INLINE void
+mget_ids(const size_t itri, size_t ids[3], void* context)
{
const struct mesh_context* ctx = context;
CHK(ids != NULL);