commit 339d4f77b30d883e15469dee20bd3de935715a77
parent 91a905be96b8839148fb4f56f931968c15302dd4
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Thu, 9 Feb 2023 18:37:59 +0100
Add a device to the lib to hold precision
Diffstat:
12 files changed, 668 insertions(+), 166 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -51,7 +51,10 @@ set(VERSION_MINOR 2)
set(VERSION_PATCH 0)
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
-set(SCPR_FILES_SRC scpr_mesh.c scpr_polygon.c)
+set(SCPR_FILES_SRC
+ scpr_device.c
+ 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)
@@ -93,6 +96,7 @@ if(NOT NO_TEST)
add_test(${_name} ${_name})
endfunction()
new_test(test_scpr_clip)
+ new_test(test_scpr_device)
new_test(test_scpr_offset)
new_test(test_scpr_mesh)
new_test(test_scpr_polygon)
diff --git a/src/scpr.h b/src/scpr.h
@@ -51,25 +51,102 @@ enum scpr_join_type {
/* Forward declaration */
struct mem_allocator;
-/* Opaque 2D closed polygon data type */
+/* Forward declaration of the star-cpr opaque data types. These data types are
+ * ref counted. Once created the caller implicitly owns the created data, i.e.
+ * its reference counter is set to 1. The scpr_<TYPE>_ref_<get|put> functions
+ * get or release a reference on the data, i.e. they increment or decrement the
+ * reference counter, respectively. When this counter reaches 0, the object is
+ * silently destroyed and cannot be used anymore. */
+struct scpr_device;
struct scpr_polygon;
-/* Opaque 2D mesh data type */
struct scpr_mesh;
+/* Input arguments of the scpr_device_create function */
+struct scpr_device_create_args {
+ struct logger* logger; /* NULL <=> default logger */
+ struct mem_allocator* allocator; /* NULL <=> default allocator */
+ int verbosity_level;
+ int precision; /* Number of decimal place preserved; in [0 8] */
+};
+#define SCPR_DEVICE_CREATE_ARGS_DEFAULT__ { \
+ NULL, NULL, 1, 6 \
+}
+static const struct scpr_device_create_args SCPR_DEVICE_CREATE_ARGS_DEFAULT =
+ SCPR_DEVICE_CREATE_ARGS_DEFAULT__;
+
BEGIN_DECLS
-/* Polygons can be made of any number of paths.
+/*******************************************************************************
+ * star-scpr Device. It is an handle toward the Stardis library. It manages the
+ * star-scpr resources.
+ ******************************************************************************/
+SCPR_API res_T
+scpr_device_create
+ (const struct scpr_device_create_args* args,
+ struct scpr_device** dev);
+
+SCPR_API res_T
+scpr_device_ref_get
+ (struct scpr_device* dev);
+
+SCPR_API res_T
+scpr_device_ref_put
+ (struct scpr_device* dev);
+
+/* Get the range for polygon and mesh vertices.
+ * The range depends on the precision parameter of the device and is
+ * [-2^(46-precision) + 2^(46-precision)]. */
+SCPR_API res_T
+scpr_device_get_range
+ (const struct scpr_device* dev,
+ double range[2]);
+
+/* Check if values are in range */
+SCPR_API res_T
+scpr_device_in_range
+ (const struct scpr_device* dev,
+ const double* values,
+ const size_t count,
+ int* in_range);
+
+/* Scale a set of values.
+ * Internal representation for vertices in star-cpr is in interger format.
+ * The process of converting reals to integers is named scaling (and the reverse
+ * process is named unscaling). */
+SCPR_API res_T
+scpr_device_scale
+ (const struct scpr_device* dev,
+ const double* values,
+ const size_t count,
+ int64_t* scaled);
+
+/* Unscale a set of values.
+ * Internal representation for vertices in star-cpr is in interger format.
+ * The process of converting reals to integers is named scaling (and the reverse
+ * process is named unscaling). */
+SCPR_API res_T
+scpr_device_unscale
+ (const struct scpr_device* dev,
+ const int64_t* values,
+ const size_t count,
+ double* unscaled);
+
+/*******************************************************************************
+ * Type of polygons, as manipulated by star-cpr.
+ * Polygons can be made of any number of paths and are subject to a range limit
+ * and a precision (see device).
* Polygons inside/outside regions are defined by their winding numbers
* considering the Even-Odd convention.
- * E.g. a CCW path inside a CW one defines a hole. */
+ * E.g. a CCW path inside a CW one defines a hole.
+ ******************************************************************************/
SCPR_API res_T
scpr_polygon_create
- (struct mem_allocator* allocator, /* May be NULL <=> Use default allocator */
+ (struct scpr_device* dev,
struct scpr_polygon** polygon);
SCPR_API res_T
scpr_polygon_create_copy
- (struct mem_allocator* allocator, /* May be NULL <=> Use default allocator */
+ (struct scpr_device* dev,
const struct scpr_polygon* src_polygon,
struct scpr_polygon** polygon);
@@ -81,13 +158,7 @@ SCPR_API res_T
scpr_polygon_ref_put
(struct scpr_polygon* polygon);
-/* To ensure constant precision, vertice coordinates are truncated, and have a
- * limited range. Range checking along with the associated truncation process
- * occur at vertices setup.
- * The allowed range is [-1e12 +1e12], and vertex coordinates are truncated
- * approximately past the 6th decimal place. It is an error to use out-of-range
- * values.
- * Also, the number of components and vertices can be changed due to a
+/* The number of components and vertices can be changed due to a
* simplification process and one should not take for granted that the number of
* components and vertices stay as provided at construction time.
* The actual counts and coordinates should be retrieved using the appropriate
@@ -133,9 +204,14 @@ scpr_polygon_eq
const struct scpr_polygon* polygon2,
int* is_eq);
+/*******************************************************************************
+ * Type of meshes, as manipulated by star-cpr.
+ * Meshes can be made of any number of triangles and are subject to a range
+ * limit and a precision (see device).
+ ******************************************************************************/
SCPR_API res_T
scpr_mesh_create
- (struct mem_allocator* allocator, /* May be NULL <=> Use default allocator */
+ (struct scpr_device* dev,
struct scpr_mesh** mesh);
SCPR_API res_T
@@ -146,8 +222,6 @@ SCPR_API res_T
scpr_mesh_ref_put
(struct scpr_mesh* mesh);
-/* In a way similar to polygons, meshes have their vertices coordinates range
- * limited to [-1e12 1e12] and truncated past the 6th decimal place. */
SCPR_API res_T
scpr_mesh_setup_indexed_vertices
(struct scpr_mesh* mesh,
diff --git a/src/scpr_c.h b/src/scpr_c.h
@@ -49,21 +49,6 @@
goto error; \
}
-/* Sets the precision parameter, as expected by Clipper2.
- * Allowed range is [-8 +8].
- * This parameter defines both the floating point precision for the coordinates
- * and the range of the coordinates.
- * With a precision of 0, coordinates are truncated to the nearest integer and
- * the coordinate range is [-INT64_MAX/4 +INT64_MAX/4] (that is approximately
- * [-2.3E18 + 2.3E18]).
- * Increasing precision by 1 adds 1 more decimal place to the coordinate
- * precision and divides the coordinate range by 10. */
-#define PRECISION 6
-
-/* Maximum range is somewhat arbitrarily set at [-1e12 + 1e12].
- * The rationale is that beyond this range accuracy decreases sharply. */
-#define RANGE_MAX 1e12
-
struct mem_allocator;
struct vertex { int64_t pos[2]; };
@@ -78,12 +63,23 @@ vertex_eq(const struct vertex* a, const struct vertex* b)
#define HTABLE_KEY_FUNCTOR_EQ vertex_eq
#include <rsys/hash_table.h>
+struct scpr_device {
+ int precision;
+ double scale;
+ double inv_scale;
+ double range[2];
+
+ ref_T ref;
+ struct mem_allocator* allocator;
+ struct logger* logger;
+};
+
struct scpr_polygon {
Clipper2Lib::Paths64 paths;
int64_t lower[2], upper[2]; /* Polygon AABB */
ref_T ref;
- struct mem_allocator* allocator;
+ struct scpr_device* device;
};
struct scpr_mesh {
@@ -91,40 +87,7 @@ struct scpr_mesh {
struct darray_size_t indices;
ref_T ref;
- struct mem_allocator* allocator;
+ struct scpr_device* device;
};
-res_T INLINE
-round_and_set_vertex
- (const double in[2],
- int64_t out[2])
-{
- /* to optimize scaling / descaling precision
- * set the scale to a power of double's radix (2) (#25) */
- double scale = pow(2, (int)log2(pow(10, PRECISION)) + 1);
- ASSERT(in && out);
- /* Check value is in-range */
- if(in[0] < -RANGE_MAX || in[0] > RANGE_MAX
- || in[1] < -RANGE_MAX || in[1] > RANGE_MAX)
- {
- return RES_BAD_ARG;
- }
- out[0] = std::llround(in[0] * scale);
- out[1] = std::llround(in[1] * scale);
- return RES_OK;
-}
-
-void INLINE
-get_vertex
- (const int64_t in[2],
- double out[2])
-{
- /* to optimize scaling / descaling precision
- * set the scale to a power of double's radix (2) (#25) */
- double inv_scale = pow(2, -(int)log2(pow(10, PRECISION)) - 1);
- ASSERT(in && out);
- out[0] = (double)in[0] * inv_scale;
- out[1] = (double)in[1] * inv_scale;
-}
-
#endif
diff --git a/src/scpr_device.c b/src/scpr_device.c
@@ -0,0 +1,189 @@
+/* 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 <polygon.h>
+#include <rsys/mem_allocator.h>
+#include <rsys/logger.h>
+#include <rsys/rsys.h>
+#include <rsys/double2.h>
+
+#undef PI
+#include <clipper2/clipper.h>
+
+#include <math.h>
+
+#ifdef OS_UNIX
+ /* On UNIX assume a VT100-like terminal emulator */
+ #define MSG_INFO_PREFIX "star-cpr (\x1b[1m\x1b[32minfo\x1b[0m): "
+ #define MSG_ERROR_PREFIX "star-cpr (\x1b[1m\x1b[31merror\x1b[0m): "
+ #define MSG_WARNING_PREFIX "star-cpr (\x1b[1m\x1b[33mwarning\x1b[0m): "
+#else
+ #define MSG_INFO_PREFIX "star-cpr (info): "
+ #define MSG_ERROR_PREFIX "star-cpr (error): "
+ #define MSG_WARNING_PREFIX "star-cpr (warning): "
+#endif
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static void
+device_release(ref_T* ref)
+{
+ struct scpr_device* device;
+ struct mem_allocator* allocator;
+ ASSERT(ref);
+ device = CONTAINER_OF(ref, struct scpr_device, ref);
+ allocator = device->allocator;
+ MEM_RM(allocator, device);
+}
+
+int INLINE
+is_in_range
+ (const double x,
+ const double range[2])
+{
+ ASSERT(range);
+ return range[0] <= x && x <= range[1];
+}
+
+/*******************************************************************************
+ * Exported functions
+ ******************************************************************************/
+res_T
+scpr_device_create
+ (const struct scpr_device_create_args* args,
+ struct scpr_device** out_device)
+{
+ struct scpr_device* device = NULL;
+ struct mem_allocator* allocator = NULL;
+ res_T res = RES_OK;
+
+ if(!args || !out_device || args->precision < 0 || args->precision > 8) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ allocator = args->allocator ? args->allocator : &mem_default_allocator;
+ device = (struct scpr_device*)MEM_CALLOC(allocator, 1, sizeof(struct scpr_device));
+ if(!device) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+ ref_init(&device->ref);
+ device->allocator = allocator;
+ device->logger = args->logger ? args->logger : LOGGER_DEFAULT;
+ device->precision = args->precision;
+ /* to optimize scaling / descaling precision
+ * set the scale to a power of double's radix (2) (#25) */
+ device->scale = pow(2, (int)log2(pow(10, device->precision)) + 1);
+ device->inv_scale = 1/device->scale;
+ device->range[1] = pow(2, 46 - device->precision);
+ device->range[0] = -device->range[1];
+
+exit:
+ if(out_device) *out_device = device;
+ return res;
+
+error:
+ if(device) {
+ SCPR(device_ref_put(device));
+ device = NULL;
+ }
+ goto exit;
+}
+
+res_T
+scpr_device_ref_get
+ (struct scpr_device* device)
+{
+ if(!device) return RES_BAD_ARG;
+ ref_get(&device->ref);
+ return RES_OK;
+}
+
+res_T
+scpr_device_ref_put
+ (struct scpr_device* device)
+{
+ if(!device) return RES_BAD_ARG;
+ ref_put(&device->ref, device_release);
+ return RES_OK;
+}
+
+res_T
+scpr_device_get_range
+ (const struct scpr_device* dev,
+ double range[2])
+{
+ if(!dev || !range) return RES_BAD_ARG;
+ d2_set(range, dev->range);
+ return RES_OK;
+}
+
+res_T
+scpr_device_in_range
+ (const struct scpr_device* dev,
+ const double* values,
+ const size_t count,
+ int* in_range)
+
+{
+ size_t i;
+ int in = 1;
+ if(!dev || !values || !in_range) return RES_BAD_ARG;
+ for(i = 0; i < count; i++) {
+ if(!is_in_range(values[i], dev->range)) {
+ in = 0;
+ break;
+ }
+ }
+ *in_range = in;
+ return RES_OK;
+}
+
+res_T
+scpr_device_scale
+ (const struct scpr_device* dev,
+ const double* values,
+ const size_t count,
+ int64_t* scaled)
+{
+ size_t i;
+ if(!dev || !values || !scaled) return RES_BAD_ARG;
+ for(i = 0; i < count; i++) {
+ if(!is_in_range(values[i], dev->range)) return RES_BAD_ARG;
+ scaled[i] = std::llround(values[i] * dev->scale);
+ }
+ return RES_OK;
+}
+
+res_T
+scpr_device_unscale
+ (const struct scpr_device* dev,
+ const int64_t* values,
+ const size_t count,
+ double* unscaled)
+{
+ size_t i;
+ if(!dev || !values || !unscaled) return RES_BAD_ARG;
+ for(i = 0; i < count; i++) {
+ unscaled[i] = (double)values[i] * dev->inv_scale;
+ }
+ return RES_OK;
+}
diff --git a/src/scpr_mesh.c b/src/scpr_mesh.c
@@ -140,11 +140,12 @@ error:
static res_T
register_paths
- (const Clipper2Lib::Paths64& paths,
+ (struct scpr_device* dev,
+ const Clipper2Lib::Paths64& paths,
struct darray_int64* coords, /* Vertex buffer */
struct darray_size_t* indices, /* Index buffer */
struct htable_vertex* vertices, /* Map a vertex to its index */
- struct polygon* polygon) /* Use to triangulate the clipped polygons */
+ struct polygon* polygon) /* Used to triangulate the clipped polygons */
{
size_t ivert;
size_t ipath;
@@ -173,7 +174,7 @@ register_paths
pos64[0] = paths[ipath][ivert].x;
pos64[1] = paths[ipath][ivert].y;
- get_vertex(pos64, posd);
+ SCPR(device_unscale(dev, pos64, 2, posd));
fpos[0] = (float)posd[0], fpos[1] = (float)posd[1];
ERR(polygon_vertex_add(polygon, fpos));
@@ -187,7 +188,7 @@ register_paths
POLYGON(vertex_get(polygon, ids[ivert], fpos));
pos[0] = (double)fpos[0];
pos[1] = (double)fpos[1];
- ERR(round_and_set_vertex(pos, pos64));
+ SCPR(device_scale(dev, pos, 2, pos64));
ERR(register_vertex(pos64, coords, indices, vertices));
}
}
@@ -199,7 +200,10 @@ error:
}
static void
-mesh_compute_aabb(const struct scpr_mesh* mesh, int64_t lower[2], int64_t upper[2])
+mesh_compute_aabb
+ (const struct scpr_mesh* mesh,
+ int64_t lower[2],
+ int64_t upper[2])
{
size_t itri, ntris, i;
@@ -214,7 +218,7 @@ mesh_compute_aabb(const struct scpr_mesh* mesh, int64_t lower[2], int64_t upper[
double pos[2];
int64_t pos64[2];
SCPR(mesh_get_position(mesh, ids[ivert], pos));
- CHK(RES_OK == round_and_set_vertex(pos, pos64));
+ SCPR(device_scale(mesh->device, pos, 2, pos64));
for(i = 0; i < 2; i++) {
if(lower[i] > pos64[i]) lower[i] = pos64[i];
if(upper[i] < pos64[i]) upper[i] = pos64[i];
@@ -227,39 +231,43 @@ static void
mesh_release(ref_T* ref)
{
struct scpr_mesh* mesh;
+ struct mem_allocator* allocator;
ASSERT(ref);
mesh = CONTAINER_OF(ref, struct scpr_mesh, ref);
+ allocator = mesh->device->allocator;
+ SCPR(device_ref_put(mesh->device));
darray_int64_release(&mesh->coords);
darray_size_t_release(&mesh->indices);
- MEM_RM(mesh->allocator, mesh);
+ MEM_RM(allocator, mesh);
}
/*******************************************************************************
* Exported functions
******************************************************************************/
res_T
-scpr_mesh_create(struct mem_allocator* mem_allocator, struct scpr_mesh** out_mesh)
+scpr_mesh_create
+ (struct scpr_device* dev,
+ struct scpr_mesh** out_mesh)
{
struct scpr_mesh* mesh = NULL;
- struct mem_allocator* allocator = NULL;
res_T res = RES_OK;
- if(!out_mesh) {
+ if(!dev || !out_mesh) {
res = RES_BAD_ARG;
goto error;
}
- allocator = mem_allocator ? mem_allocator : &mem_default_allocator;
mesh = (struct scpr_mesh*)
- MEM_CALLOC(allocator, 1, sizeof(struct scpr_mesh));
+ MEM_CALLOC(dev->allocator, 1, sizeof(struct scpr_mesh));
if(!mesh) {
res = RES_MEM_ERR;
goto error;
}
- darray_int64_init(mesh->allocator, &mesh->coords);
- darray_size_t_init(mesh->allocator, &mesh->indices);
ref_init(&mesh->ref);
- mesh->allocator = allocator;
+ mesh->device = dev;
+ SCPR(device_ref_get(dev));
+ darray_int64_init(dev->allocator, &mesh->coords);
+ darray_size_t_init(dev->allocator, &mesh->indices);
exit:
if(out_mesh) *out_mesh = mesh;
@@ -316,7 +324,7 @@ scpr_mesh_setup_indexed_vertices
FOR_EACH(i, 0, nverts) {
double posd[2];
get_position(i, posd, data);
- ERR(round_and_set_vertex(posd, pos + i*2));
+ ERR(scpr_device_scale(mesh->device, posd, 2, pos + i*2));
}
/* Fetch mesh indices */
@@ -386,7 +394,7 @@ scpr_mesh_get_position
if(ivert >= nverts) return RES_BAD_ARG;
pos64[0] = darray_int64_cdata_get(&mesh->coords)[i+0];
pos64[1] = darray_int64_cdata_get(&mesh->coords)[i+1];
- get_vertex(pos64, pos);
+ SCPR(device_unscale(mesh->device, pos64, 2, pos));
return RES_OK;
}
@@ -407,6 +415,7 @@ scpr_mesh_clip
Clipper2Lib::Path64 tmp;
Clipper2Lib::ClipType clip_type; /* Type of clipping to perform */
size_t itri, ntris, ivert;
+ struct mem_allocator* allocator;
int i;
res_T res = RES_OK;
@@ -414,11 +423,12 @@ scpr_mesh_clip
if(!mesh || !poly_desc || (unsigned)op >= SCPR_OPERATIONS_COUNT__)
return RES_BAD_ARG;
+ allocator = mesh->device->allocator;
clip_type = scpr_operation_to_clip_type(op);
- darray_int64_init(mesh->allocator, &coords);
- darray_size_t_init(mesh->allocator, &indices);
- htable_vertex_init(mesh->allocator, &vertices);
+ darray_int64_init(allocator, &coords);
+ darray_size_t_init(allocator, &indices);
+ htable_vertex_init(allocator, &vertices);
if(aabb_is_degenerated(poly_desc->lower, poly_desc->upper)) goto exit;
@@ -432,7 +442,7 @@ scpr_mesh_clip
}
/* Create the polygon structure used to triangulate the clipped polygons */
- ERR(polygon_create(mesh->allocator, &polygon));
+ ERR(polygon_create(allocator, &polygon));
/* Clip the triangles of the mesh */
SCPR(mesh_get_triangles_count(mesh, &ntris));
@@ -446,9 +456,9 @@ scpr_mesh_clip
SCPR(mesh_get_position(mesh, ids[0], tri[0]));
SCPR(mesh_get_position(mesh, ids[1], tri[1]));
SCPR(mesh_get_position(mesh, ids[2], tri[2]));
- ERR(round_and_set_vertex(tri[0], tri64[0]));
- ERR(round_and_set_vertex(tri[1], tri64[1]));
- ERR(round_and_set_vertex(tri[2], tri64[2]));
+ SCPR(device_scale(mesh->device, tri[0], 2, tri64[0]));
+ SCPR(device_scale(mesh->device, tri[1], 2, tri64[1]));
+ SCPR(device_scale(mesh->device, tri[2], 2, tri64[2]));
triangle_compute_aabb(tri64, lower, upper);
/* Do not clip triangles that do not intersect the clip AABB */
@@ -477,7 +487,7 @@ scpr_mesh_clip
clipper.Execute(clip_type, Clipper2Lib::FillRule::EvenOdd, output);
/* Register the resulting clipped polygons */
- ERR(register_paths (output, &coords, &indices, &vertices, polygon));
+ ERR(register_paths(mesh->device, output, &coords, &indices, &vertices, polygon));
}
ERR(darray_int64_copy_and_clear(&mesh->coords, &coords));
diff --git a/src/scpr_polygon.c b/src/scpr_polygon.c
@@ -18,6 +18,7 @@
#include <new>
#include <polygon.h>
+#include <rsys/logger.h>
#include <rsys/mem_allocator.h>
#include <rsys/rsys.h>
#include <rsys/double2.h>
@@ -47,11 +48,14 @@ static void
polygon_release(ref_T* ref)
{
struct scpr_polygon* polygon;
+ struct mem_allocator* allocator;
ASSERT(ref);
polygon = CONTAINER_OF(ref, struct scpr_polygon, ref);
+ allocator = polygon->device->allocator;
+ SCPR(device_ref_put(polygon->device));
/* Call destructor for paths */
polygon->paths.Clipper2Lib::Paths64::~Paths64();
- MEM_RM(polygon->allocator, polygon);
+ MEM_RM(allocator, polygon);
}
static int
@@ -110,27 +114,26 @@ one_path_is_eq
******************************************************************************/
res_T
scpr_polygon_create
- (struct mem_allocator* mem_allocator,
+ (struct scpr_device* dev,
struct scpr_polygon** out_polygon)
{
struct scpr_polygon* polygon = NULL;
- struct mem_allocator* allocator = NULL;
res_T res = RES_OK;
- if(!out_polygon) {
+ if(!dev || !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));
+ MEM_CALLOC(dev->allocator, 1, sizeof(struct scpr_polygon));
if(!polygon) {
res = RES_MEM_ERR;
goto error;
}
ref_init(&polygon->ref);
- polygon->allocator = allocator;
+ polygon->device = dev;
+ SCPR(device_ref_get(dev));
/* Allocate paths the C++ way (placement new) */
new (&polygon->paths) Clipper2Lib::PathsD;
polygon->lower[0] = polygon->lower[1] = INT64_MAX;
@@ -176,10 +179,9 @@ scpr_polygon_setup_indexed_vertices
void* data)
{
size_t c;
- /* to optimize scaling / descaling precision
- * set the scale to a power of double's radix (2) (#25) */
- double inv_scale = pow(2, -(int)log2(pow(10, PRECISION)) - 1);
+ struct scpr_device* dev;
Clipper2Lib::Paths64 paths;
+ int changedc, changedv = 0;
res_T res = RES_OK;
if(!polygon || !get_nverts || !get_position || !data) {
@@ -187,6 +189,7 @@ scpr_polygon_setup_indexed_vertices
goto error;
}
+ dev = polygon->device;
TRY(paths.resize(ncomponents));
FOR_EACH(c, 0, ncomponents) {
@@ -203,7 +206,7 @@ scpr_polygon_setup_indexed_vertices
Clipper2Lib::Point64 pt;
get_position(c, i, tmp, data);
/* Check range and truncate precision to ensure further consistency */
- ERR(round_and_set_vertex(tmp, tmp64));
+ ERR(scpr_device_scale(dev, tmp, 2, tmp64));
pt.x = tmp64[0];
pt.y = tmp64[1];
paths[c][i] = pt;
@@ -211,8 +214,19 @@ scpr_polygon_setup_indexed_vertices
}
/* Merge vertices, ... */
- TRY(paths = Clipper2Lib::SimplifyPaths(paths, inv_scale));
+ TRY(paths = Clipper2Lib::SimplifyPaths(paths, dev->inv_scale));
polygon->paths = std::move(paths);
+ changedc = (ncomponents != polygon->paths.size());
+ for(c = 0; !changedv && c < paths.size(); c++) {
+ size_t nv;
+ get_nverts(c, &nv, data);
+ changedv |= (nv != polygon->paths[c].size());
+ }
+ if(changedc || changedv) {
+ /* TODO: emit a warning log */
+ logger_print(dev->logger, LOG_WARNING,
+ "Polygon has been simplified. Original counts are no longer valid.\n");
+ }
/* Build bounding box */
polygon->lower[0] = polygon->lower[1] = INT64_MAX;
@@ -245,7 +259,7 @@ error:
res_T
scpr_polygon_create_copy
- (struct mem_allocator* allocator,
+ (struct scpr_device* dev,
const struct scpr_polygon* src_polygon,
struct scpr_polygon** out_polygon)
{
@@ -253,11 +267,11 @@ scpr_polygon_create_copy
int i;
res_T res = RES_OK;
- if(!src_polygon || !out_polygon) {
+ if(!dev || !src_polygon || !out_polygon) {
res = RES_BAD_ARG;
goto error;
}
- ERR(scpr_polygon_create(allocator, ©));
+ ERR(scpr_polygon_create(dev, ©));
copy->paths = src_polygon->paths;
for(i = 0; i < 2; i++) {
@@ -318,7 +332,7 @@ scpr_polygon_get_position
pt = &polygon->paths[icomponent][i];
pos64[0] = pt->x;
pos64[1] = pt->y;
- get_vertex(pos64, pos);
+ SCPR(device_unscale(polygon->device, pos64, 2, pos));
return RES_OK;
}
@@ -330,11 +344,10 @@ scpr_offset_polygon
{
size_t c;
Clipper2Lib::Path64 tmp;
+ struct scpr_device* dev;
Clipper2Lib::JoinType cjt;
Clipper2Lib::Paths64 polygon;
- /* to optimize scaling / descaling precision
- * set the scale to a power of double's radix (2) (#25) */
- double scale = pow(2, (int)log2(pow(10, PRECISION)) + 1);
+ int64_t offset64;
res_T res = RES_OK;
if(!poly_desc) {
@@ -342,12 +355,16 @@ scpr_offset_polygon
goto error;
}
+ dev = poly_desc->device;
+
/* Check offset polygon will be in-range */
if(offset > 0) {
int i;
+ double range[2];
+ SCPR(device_get_range(dev, range));
for(i = 0; i < 2; i++) {
- if((double)poly_desc->lower[i] - offset < -RANGE_MAX
- || (double)poly_desc->upper[i] + offset > RANGE_MAX)
+ if((double)poly_desc->lower[i] - offset < range[0]
+ || (double)poly_desc->upper[i] + offset > range[1])
{
res = RES_BAD_ARG;
goto error;
@@ -366,9 +383,10 @@ scpr_offset_polygon
goto error;
}
+ ERR(scpr_device_scale(dev, &offset, 1, &offset64));
cjt = scpr_join_type_to_clipper_join_type(join_type);
TRY(poly_desc->paths = Clipper2Lib::InflatePaths(poly_desc->paths,
- offset * scale, cjt, Clipper2Lib::EndType::Polygon));
+ (double)offset64, cjt, Clipper2Lib::EndType::Polygon));
/* Rebuild AABB */
poly_desc->lower[0] = poly_desc->lower[1] = INT64_MAX;
@@ -440,5 +458,3 @@ exit:
error:
goto exit;
}
-
-
diff --git a/src/test_scpr_clip.c b/src/test_scpr_clip.c
@@ -51,13 +51,15 @@ dump_obj(FILE* stream, const struct scpr_mesh* mesh)
static void
test_triangle
- (struct mem_allocator* allocator,
+ (struct scpr_device* dev,
+ struct mem_allocator* allocator,
struct scpr_mesh* mesh)
{
const double triangle_pos1[] = { 0, 0, 0, 1, 1, 0 };
- const double triangle_pos2[] = { 0e20, 0e20, 0e20, 1e20, 1e20, 0e20 };
+ double triangle_pos2[] = { 0, 0, 0, 1e20, 1e20, 0}; /* To be replaced */
const size_t triangle_ids[] = { 0, 1, 2 };
double** clip_pos;
+ double range[2];
size_t nverts[] = { 3 };
size_t ncomps = 1;
const double clip_pos0[] = { -1.0, 0.25, 1.0, 0.75, 1, 0.25 };
@@ -66,6 +68,10 @@ test_triangle
struct mesh_context mctx;
size_t ntris;
+ /* Set out-of-range value in triangle_pos2 */
+ SCPR(device_get_range(dev, range));
+ triangle_pos2[3] = triangle_pos2[4] = range[1] + 1;
+
clip_pos = (double**)MEM_CALLOC(allocator, ncomps, sizeof(*clip_pos));
*clip_pos = (double*)MEM_CALLOC(allocator, nverts[0], 2*sizeof(**clip_pos));
memcpy(*clip_pos, clip_pos0, 2*nverts[0]*sizeof(**clip_pos));
@@ -73,7 +79,7 @@ test_triangle
pctx.coords = clip_pos;
pctx.nverts = nverts;
pctx.ncomps = ncomps;
- OK(scpr_polygon_create(allocator, &poly));
+ OK(scpr_polygon_create(dev, &poly));
OK(scpr_polygon_setup_indexed_vertices(poly, ncomps, pget_nverts, pget_pos, &pctx));
/* Check out-of-range */
@@ -109,7 +115,8 @@ test_triangle
static void
test_quad
- (struct mem_allocator* allocator,
+ (struct scpr_device* dev,
+ 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 };
@@ -129,7 +136,7 @@ test_quad
pctx.coords = clip_pos;
pctx.nverts = nverts;
pctx.ncomps = ncomps;
- OK(scpr_polygon_create(allocator, &poly));
+ OK(scpr_polygon_create(dev, &poly));
OK(scpr_polygon_setup_indexed_vertices(poly, ncomps, pget_nverts, pget_pos, &pctx));
mctx.coords = quad_pos;
@@ -150,7 +157,8 @@ test_quad
static void
test_disk
- (struct mem_allocator* allocator,
+ (struct scpr_device* dev,
+ struct mem_allocator* allocator,
struct scpr_mesh* mesh)
{
double** clip_pos;
@@ -220,7 +228,7 @@ test_disk
pctx.coords = clip_pos;
pctx.nverts = nverts;
pctx.ncomps = ncomps;
- OK(scpr_polygon_create(allocator, &poly));
+ OK(scpr_polygon_create(dev, &poly));
OK(scpr_polygon_setup_indexed_vertices(poly, ncomps, pget_nverts, pget_pos, &pctx));
mctx.coords = pos;
@@ -245,18 +253,23 @@ int
main(int argc, char** argv)
{
struct mem_allocator allocator;
+ struct scpr_device_create_args args = SCPR_DEVICE_CREATE_ARGS_DEFAULT;
+ struct scpr_device* dev;
struct scpr_mesh* mesh;
(void)argc, (void)argv;
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
- OK(scpr_mesh_create(&allocator, &mesh));
+ args.allocator = &allocator;
+ OK(scpr_device_create(&args, &dev));
+ OK(scpr_mesh_create(dev, &mesh));
- test_triangle(&allocator, mesh);
- test_quad(&allocator, mesh);
- test_disk(&allocator, mesh);
+ test_triangle(dev, &allocator, mesh);
+ test_quad(dev, &allocator, mesh);
+ test_disk(dev, &allocator, mesh);
OK(scpr_mesh_ref_put(mesh));
+ OK(scpr_device_ref_put(dev));
check_memory_allocator(&allocator);
mem_shutdown_proxy_allocator(&allocator);
diff --git a/src/test_scpr_device.c b/src/test_scpr_device.c
@@ -0,0 +1,108 @@
+/* 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/>. */
+
+#define _POSIX_C_SOURCE 200112L
+
+#include "scpr.h"
+#include "test_scpr_utils.h"
+
+#include <rsys/rsys.h>
+
+#include <memory.h>
+
+int
+main(int argc, char** argv)
+{
+ struct mem_allocator allocator;
+ struct scpr_device_create_args args = SCPR_DEVICE_CREATE_ARGS_DEFAULT;
+ struct scpr_device* dev;
+ double r[2];
+ const double d[5] = { 0, 1, 2, 3, 4};
+ double tmpd[5];
+ const int64_t i64[5] = { 0, 1, 2, 3, 4};
+ int64_t tmp64[5];
+ int in;
+ (void)argc, (void)argv;
+
+ mem_init_proxy_allocator(&allocator, &mem_default_allocator);
+
+ args.allocator = &allocator;
+
+ BAD(scpr_device_create(NULL, NULL));
+ BAD(scpr_device_create(&args, NULL));
+ BAD(scpr_device_create(NULL, &dev));
+
+ args.precision = -1;
+ BAD(scpr_device_create(&args, &dev));
+
+ args.precision = SCPR_DEVICE_CREATE_ARGS_DEFAULT.precision;
+ OK(scpr_device_create(&args, &dev));
+
+ BAD(scpr_device_ref_get(NULL));
+ OK(scpr_device_ref_get(dev));
+
+ BAD(scpr_device_ref_put(NULL));
+ OK(scpr_device_ref_put(dev));
+
+ BAD(scpr_device_get_range(NULL, NULL));
+ BAD(scpr_device_get_range(NULL, r));
+ BAD(scpr_device_get_range(dev, NULL));
+ OK(scpr_device_get_range(dev, r));
+
+ BAD(scpr_device_in_range(NULL, NULL, 5, NULL));
+ BAD(scpr_device_in_range(NULL, NULL, 5, &in));
+ BAD(scpr_device_in_range(NULL, d, 5, NULL));
+ BAD(scpr_device_in_range(dev, NULL, 5, NULL));
+ BAD(scpr_device_in_range(NULL, d, 5, &in));
+ BAD(scpr_device_in_range(dev, NULL, 5, &in));
+ BAD(scpr_device_in_range(dev, d, 5, NULL));
+ OK(scpr_device_in_range(dev, d, 5, &in));
+ CHK(in);
+ /* With out_of_range value */
+ memcpy(tmpd, d, sizeof(d));
+ tmpd[3] = r[1] + 1;
+ OK(scpr_device_in_range(dev, tmpd, 5, &in));
+ CHK(!in);
+
+ BAD(scpr_device_scale(NULL, NULL, 5, NULL));
+ BAD(scpr_device_scale(NULL, NULL, 5, tmp64));
+ BAD(scpr_device_scale(NULL, d, 5, NULL));
+ BAD(scpr_device_scale(dev, NULL, 5, NULL));
+ BAD(scpr_device_scale(NULL, d, 5, tmp64));
+ BAD(scpr_device_scale(dev, NULL, 5, tmp64));
+ BAD(scpr_device_scale(dev, d, 5, NULL));
+ OK(scpr_device_scale(dev, d, 5, tmp64));
+ /* With out_of_range value */
+ memcpy(tmpd, d, sizeof(d));
+ tmpd[3] = r[1] + 1;
+ BAD(scpr_device_scale(dev, tmpd, 5, tmp64));
+
+ BAD(scpr_device_unscale(NULL, NULL, 5, NULL));
+ BAD(scpr_device_unscale(NULL, NULL, 5, tmpd));
+ BAD(scpr_device_unscale(NULL, i64, 5, NULL));
+ BAD(scpr_device_unscale(dev, NULL, 5, NULL));
+ BAD(scpr_device_unscale(NULL, i64, 5, tmpd));
+ BAD(scpr_device_unscale(dev, NULL, 5, tmpd));
+ BAD(scpr_device_unscale(dev, i64, 5, NULL));
+ OK(scpr_device_unscale(dev, i64, 5, tmpd));
+
+ OK(scpr_device_ref_put(dev));
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHK(mem_allocated_size() == 0);
+ return 0;
+}
+
diff --git a/src/test_scpr_mesh.c b/src/test_scpr_mesh.c
@@ -48,6 +48,8 @@ main(int argc, char** argv)
size_t ids[3];
double pos[2];
size_t i, n;
+ struct scpr_device_create_args args = SCPR_DEVICE_CREATE_ARGS_DEFAULT;
+ struct scpr_device* dev;
struct mem_allocator allocator;
struct mesh_context ctx;
struct scpr_mesh* mesh;
@@ -55,9 +57,12 @@ main(int argc, char** argv)
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
+ args.allocator = &allocator;
+ OK(scpr_device_create(&args, &dev));
+
BAD(scpr_mesh_create(NULL, NULL));
- BAD(scpr_mesh_create(&allocator, NULL));
- OK(scpr_mesh_create(NULL, &mesh));
+ BAD(scpr_mesh_create(dev, NULL));
+ OK(scpr_mesh_create(dev, &mesh));
BAD(scpr_mesh_ref_get(NULL));
OK(scpr_mesh_ref_get(mesh));
@@ -65,7 +70,7 @@ main(int argc, char** argv)
OK(scpr_mesh_ref_put(mesh));
OK(scpr_mesh_ref_put(mesh));
- OK(scpr_mesh_create(&allocator, &mesh));
+ OK(scpr_mesh_create(dev, &mesh));
ctx.coords = coords;
ctx.nverts = nverts;
@@ -188,6 +193,7 @@ main(int argc, char** argv)
}
OK(scpr_mesh_ref_put(mesh));
+ OK(scpr_device_ref_put(dev));
check_memory_allocator(&allocator);
mem_shutdown_proxy_allocator(&allocator);
diff --git a/src/test_scpr_offset.c b/src/test_scpr_offset.c
@@ -35,35 +35,102 @@ test_single(void)
2.0, 2.0,
2.0, -1.0
};
- const double coords2[] = {
+ double coords2[] = {
0.12345678901234, 0.0,
0.0, 1.0,
- 1.0, 1000000000000,
+ 1.0, 1000000000000, /* To be replaced */
1.0, 0.0
};
- const double coords2_reverse[] = {
+ double coords2_reverse[] = {
0.12345678901234, 0.0,
1.0, 0.0,
- 1.0, 1000000000000,
+ 1.0, 1000000000000, /* To be replaced */
0.0, 1.0
};
+ double coords3[112] = {
+ 1454.65, 1289.72,
+ 1455.91, 1303.38,
+ 1449.01, 1304.09,
+ 1449.82, 1316.24,
+ 1450.17, 1321.71,
+ 1447.09, 1322.02,
+ 1447.46, 1327.61,
+ 1447.90, 1333.96,
+ 1448.08, 1336.94,
+ 1448.34, 1341.45,
+ 1449.84, 1364.03,
+ 1450.32, 1371.41,
+ 1450.68, 1376.57,
+ 1450.96, 1381.84,
+ 1451.19, 1385.23,
+ 1451.32, 1387.00,
+ 1457.16, 1386.79,
+ 1456.88, 1381.42,
+ 1464.75, 1380.91,
+ 1464.39, 1375.95,
+ 1467.66, 1375.64,
+ 1470.14, 1375.43,
+ 1470.05, 1372.20,
+ 1467.48, 1372.41,
+ 1467.30, 1370.27,
+ 1467.48, 1370.27,
+ 1465.33, 1340.27,
+ 1478.67, 1339.29,
+ 1478.40, 1337.46,
+ 1472.30, 1337.88,
+ 1472.22, 1337.17,
+ 1469.30, 1337.38,
+ 1469.11, 1335.14,
+ 1454.35, 1336.08,
+ 1454.17, 1333.45,
+ 1459.21, 1333.14,
+ 1460.72, 1333.03,
+ 1460.45, 1330.30,
+ 1458.94, 1330.40,
+ 1458.50, 1324.54,
+ 1460.17, 1324.33,
+ 1459.91, 1320.99,
+ 1461.94, 1320.78,
+ 1461.66, 1315.12,
+ 1461.48, 1312.48,
+ 1460.34, 1312.59,
+ 1459.17, 1298.72,
+ 1525.39, 1290.04,
+ 1528.51, 1314.63,
+ 1543.99, 1312.59,
+ 1540.24, 1281.82,
+ 1528.96, 1283.36,
+ 1524.59, 1283.96,
+ 1524.86, 1286.19,
+ 1522.73, 1286.50,
+ 1521.85, 1280.52
+ };
double** coords;
+ double range[2];
size_t nverts[] = { 4 };
- size_t ncomps = 1;
+ size_t count, ncomps = 1;
struct mem_allocator allocator;
struct polygon_context ctx;
struct scpr_polygon* polygon;
struct scpr_polygon* expected;
+ struct scpr_device_create_args args = SCPR_DEVICE_CREATE_ARGS_DEFAULT;
+ struct scpr_device* dev;
int eq;
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
+ args.allocator = &allocator;
+ OK(scpr_device_create(&args, &dev));
+
+ /* Set barely in-range value in coords2 */
+ SCPR(device_get_range(dev, range));
+ coords2[5] = coords2_reverse[5] = range[1];
coords = (double**)MEM_CALLOC(&allocator, ncomps, sizeof(*coords));
*coords = (double*)MEM_CALLOC(&allocator, nverts[0], 2*sizeof(**coords));
memcpy(*coords, coords0, 2*nverts[0]*sizeof(**coords));
- OK(scpr_polygon_create(&allocator, &polygon));
- OK(scpr_polygon_create(&allocator, &expected));
+ OK(scpr_polygon_create(dev, &polygon));
+ OK(scpr_polygon_create(dev, &expected));
ctx.coords = coords;
ctx.nverts = nverts;
@@ -76,7 +143,7 @@ test_single(void)
OK(scpr_offset_polygon(polygon, 0, SCPR_JOIN_MITER));
OK(scpr_polygon_eq(polygon, expected, &eq));
CHK(eq);
- CHK(check_stability(polygon));
+ CHK(check_stability(dev, polygon));
/* Offset 1 */
memcpy(*coords, coords1, 2*nverts[0]*sizeof(**coords));
@@ -85,7 +152,7 @@ test_single(void)
OK(scpr_offset_polygon(polygon, 1, SCPR_JOIN_MITER));
OK(scpr_polygon_eq(polygon, expected, &eq));
CHK(eq);
- CHK(check_stability(polygon));
+ CHK(check_stability(dev, polygon));
/* Offset -1: back to original polygon */
memcpy(*coords, coords0, 2*nverts[0]*sizeof(**coords));
@@ -94,14 +161,14 @@ test_single(void)
OK(scpr_offset_polygon(polygon, -1, SCPR_JOIN_MITER));
OK(scpr_polygon_eq(polygon, expected, &eq));
CHK(eq);
- CHK(check_stability(polygon));
+ CHK(check_stability(dev, polygon));
/* Non representable offset: truncation will ensure stability */
OK(scpr_offset_polygon(polygon, 0.123456789, SCPR_JOIN_MITER));
OK(scpr_offset_polygon(expected, 0.123457, SCPR_JOIN_MITER));
OK(scpr_polygon_eq(polygon, expected, &eq));
CHK(eq);
- CHK(check_stability(polygon));
+ CHK(check_stability(dev, polygon));
/* Offset -5: empty polygon */
ncomps = 0;
@@ -111,7 +178,7 @@ test_single(void)
OK(scpr_offset_polygon(polygon, -5, SCPR_JOIN_MITER));
OK(scpr_polygon_eq(polygon, expected, &eq));
CHK(eq);
- CHK(check_stability(polygon));
+ CHK(check_stability(dev, polygon));
/* Check coordinates barely in-range */
memcpy(*coords, coords2, 2*nverts[0]*sizeof(**coords));
@@ -126,7 +193,7 @@ test_single(void)
OK(scpr_offset_polygon(polygon, 0, SCPR_JOIN_MITER));
OK(scpr_polygon_eq(polygon, expected, &eq));
CHK(eq);
- CHK(check_stability(polygon));
+ CHK(check_stability(dev, polygon));
/* Check non-effect of CW/CCW */
memcpy(*coords, coords2_reverse, 2*nverts[0]*sizeof(**coords));
@@ -134,13 +201,26 @@ test_single(void)
OK(scpr_offset_polygon(polygon, 0, SCPR_JOIN_MITER));
OK(scpr_polygon_eq(polygon, expected, &eq));
CHK(eq);
- CHK(check_stability(polygon));
+ CHK(check_stability(dev, polygon));
/* Check out of range after offset being detected */
BAD(scpr_offset_polygon(polygon, 1, SCPR_JOIN_MITER));
+ /* Check a polygon that used to produce a wrong result */
+ ctx.nverts[0] = 56;
+ coords[0] = (double*)MEM_REALLOC(&allocator, coords[0], nverts[0]*2*sizeof(**coords));
+ memcpy(*coords, coords3, 2 * ctx.nverts[0] * sizeof(**coords));
+ OK(scpr_polygon_setup_indexed_vertices(polygon, ncomps, pget_nverts, pget_pos, &ctx));
+ OK(scpr_offset_polygon(polygon, -0.2, SCPR_JOIN_MITER));
+ OK(scpr_polygon_get_components_count(polygon, &count));
+ CHK(count == 1);
+ OK(scpr_polygon_get_vertices_count(polygon, 0, &count));
+ /* Vertice count should remain unchanged */
+ CHK(count == ctx.nverts[0]);
+
/* Cleanup */
OK(scpr_polygon_ref_put(polygon));
+ OK(scpr_device_ref_put(dev));
OK(scpr_polygon_ref_put(expected));
MEM_RM(&allocator, *coords);
@@ -191,9 +271,13 @@ test_double(void)
struct polygon_context ctx;
struct scpr_polygon* polygon;
struct scpr_polygon* expected;
+ struct scpr_device_create_args args = SCPR_DEVICE_CREATE_ARGS_DEFAULT;
+ struct scpr_device* dev;
int eq;
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
+ args.allocator = &allocator;
+ OK(scpr_device_create(&args, &dev));
coords = (double**)MEM_CALLOC(&allocator, ncomps, sizeof(*coords));
*coords = (double*)MEM_CALLOC(&allocator, nverts[0], 2*sizeof(**coords));
@@ -201,8 +285,8 @@ test_double(void)
memcpy(*coords, coords0, 2*nverts[0]*sizeof(**coords));
memcpy(*(coords+1), coords1, 2*nverts[1]*sizeof(**coords));
- OK(scpr_polygon_create(&allocator, &polygon));
- OK(scpr_polygon_create(&allocator, &expected));
+ OK(scpr_polygon_create(dev, &polygon));
+ OK(scpr_polygon_create(dev, &expected));
ctx.coords = coords;
ctx.nverts = nverts;
@@ -254,6 +338,7 @@ test_double(void)
CHK(eq);
OK(scpr_polygon_ref_put(polygon));
+ OK(scpr_device_ref_put(dev));
OK(scpr_polygon_ref_put(expected));
MEM_RM(&allocator, *coords);
@@ -305,9 +390,13 @@ test_internal(void)
struct polygon_context ctx;
struct scpr_polygon* polygon;
struct scpr_polygon* expected;
+ struct scpr_device_create_args args = SCPR_DEVICE_CREATE_ARGS_DEFAULT;
+ struct scpr_device* dev;
int eq;
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
+ args.allocator = &allocator;
+ OK(scpr_device_create(&args, &dev));
coords = (double**)MEM_CALLOC(&allocator, ncomps, sizeof(*coords));
*coords = (double*)MEM_CALLOC(&allocator, nverts[0], 2*sizeof(**coords));
@@ -315,8 +404,8 @@ test_internal(void)
memcpy(*coords, coords0, 2*nverts[0]*sizeof(**coords));
memcpy(*(coords+1), coords1, 2*nverts[1]*sizeof(**coords));
- OK(scpr_polygon_create(&allocator, &polygon));
- OK(scpr_polygon_create(&allocator, &expected));
+ OK(scpr_polygon_create(dev, &polygon));
+ OK(scpr_polygon_create(dev, &expected));
ctx.coords = coords;
ctx.nverts = nverts;
@@ -375,6 +464,7 @@ test_internal(void)
OK(scpr_polygon_ref_put(polygon));
OK(scpr_polygon_ref_put(expected));
+ OK(scpr_device_ref_put(dev));
MEM_RM(&allocator, *coords);
MEM_RM(&allocator, *(coords+1));
diff --git a/src/test_scpr_polygon.c b/src/test_scpr_polygon.c
@@ -38,24 +38,27 @@ main(int argc, char** argv)
1.0, 1.0,
0.0, 1.0
};
- const double coords1[] = {
+ double coords1[] = {
0.0, 0.0,
0.5, 0.0,
0.0, 1.0,
1.0, 1.0,
- 1.0, 1000000000001,
+ 1.0, 1000000000001, /* To be replaced */
1.0, 0.0
};
double** coords;
size_t nverts[] = { 6 };
size_t ncomps = 1;
- double pos[2];
+ double pos[2], range[2];
size_t i, c, n;
struct mem_allocator allocator;
struct polygon_context ctx;
struct scpr_polygon* polygon;
struct scpr_polygon* copy;
- int eq;
+ struct scpr_device* dev;
+ struct scpr_device_create_args args = SCPR_DEVICE_CREATE_ARGS_DEFAULT;
+ int eq, in;
+ double low[2] = {0, 0}, up[2] = {1, 1};
(void)argc, (void)argv;
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
@@ -64,10 +67,18 @@ main(int argc, char** argv)
*coords = (double*)MEM_CALLOC(&allocator, nverts[0], 2*sizeof(**coords));
memcpy(*coords, coords0, 2*nverts[0]*sizeof(**coords));
+ args.allocator = &allocator;
+ args.precision = SCPR_DEVICE_CREATE_ARGS_DEFAULT.precision;
+ OK(scpr_device_create(&args, &dev));
+
+ /* Set out-of-range value in coords1 */
+ SCPR(device_get_range(dev, range));
+ coords1[9] = range[1] + 1;
+
BAD(scpr_polygon_create(NULL, NULL));
- BAD(scpr_polygon_create(&allocator, NULL));
- OK(scpr_polygon_create(NULL, &polygon));
- OK(scpr_polygon_create(NULL, ©));
+ BAD(scpr_polygon_create(dev, NULL));
+ OK(scpr_polygon_create(dev, &polygon));
+ OK(scpr_polygon_create(dev, ©));
OK(scpr_polygon_ref_put(copy));
BAD(scpr_polygon_ref_get(NULL));
@@ -76,7 +87,7 @@ main(int argc, char** argv)
OK(scpr_polygon_ref_put(polygon));
OK(scpr_polygon_ref_put(polygon));
- OK(scpr_polygon_create(&allocator, &polygon));
+ OK(scpr_polygon_create(dev, &polygon));
OK(scpr_polygon_get_components_count(polygon, &n));
CHK(n == 0);
@@ -111,6 +122,27 @@ main(int argc, char** argv)
CHK(n == sizeof(coords0_reduced)/(2*sizeof(*coords0_reduced)));
#undef SETUP
+ BAD(scpr_polygon_in_bbox(NULL, NULL, NULL, NULL));
+ BAD(scpr_polygon_in_bbox(NULL, NULL, NULL, &in));
+ BAD(scpr_polygon_in_bbox(NULL, NULL, up, NULL));
+ BAD(scpr_polygon_in_bbox(NULL, NULL, up, &in));
+ BAD(scpr_polygon_in_bbox(NULL, low, NULL, NULL));
+ BAD(scpr_polygon_in_bbox(NULL, low, NULL, &in));
+ BAD(scpr_polygon_in_bbox(NULL, low, up, NULL));
+ BAD(scpr_polygon_in_bbox(NULL, low, up, &in));
+ BAD(scpr_polygon_in_bbox(polygon, NULL, NULL, NULL));
+ BAD(scpr_polygon_in_bbox(polygon, NULL, NULL, &in));
+ BAD(scpr_polygon_in_bbox(polygon, NULL, up, NULL));
+ BAD(scpr_polygon_in_bbox(polygon, NULL, up, &in));
+ BAD(scpr_polygon_in_bbox(polygon, low, NULL, NULL));
+ BAD(scpr_polygon_in_bbox(polygon, low, NULL, &in));
+ OK(scpr_polygon_in_bbox(polygon, low, up, &in));
+ CHK(in);
+ /* With smaller box */
+ up[0] = 0.5;
+ OK(scpr_polygon_in_bbox(polygon, low, up, &in));
+ CHK(!in);
+
BAD(scpr_polygon_get_components_count(NULL, NULL));
BAD(scpr_polygon_get_components_count(polygon, NULL));
BAD(scpr_polygon_get_components_count(NULL, &n));
@@ -165,7 +197,7 @@ main(int argc, char** argv)
BAD(scpr_polygon_create_copy(NULL, NULL, NULL));
BAD(scpr_polygon_create_copy(NULL, NULL, ©));
BAD(scpr_polygon_create_copy(NULL, polygon, NULL));
- OK(scpr_polygon_create_copy(NULL, polygon, ©));
+ OK(scpr_polygon_create_copy(dev, polygon, ©));
OK(scpr_polygon_eq(polygon, copy, &eq));
CHK(eq);
@@ -174,6 +206,7 @@ main(int argc, char** argv)
BAD(scpr_offset_polygon(NULL, 0, SCPR_JOIN_MITER));
OK(scpr_offset_polygon(polygon, 0, SCPR_JOIN_MITER));
+ OK(scpr_device_ref_put(dev));
OK(scpr_polygon_ref_put(polygon));
OK(scpr_polygon_ref_put(copy));
diff --git a/src/test_scpr_utils.h b/src/test_scpr_utils.h
@@ -101,14 +101,12 @@ check_memory_allocator(struct mem_allocator* allocator)
INLINE int
check_stability
- (const struct scpr_polygon* polygon)
+ (struct scpr_device* dev,
+ const struct scpr_polygon* polygon)
{
res_T res = RES_OK;
- /* to optimize scaling / descaling precision
- * set the scale to a power of double's radix (2) (#25) */
- double scale = pow(2, (int)log2(pow(10, 6)) + 1);
size_t i, j, ccount, vcount;
- ASSERT(polygon);
+ ASSERT(dev && polygon);
ERR(scpr_polygon_get_components_count(polygon, &ccount));
@@ -118,10 +116,8 @@ check_stability
double pt[2], tmp[2];
int64_t tmp2[2];
ERR(scpr_polygon_get_position(polygon, i, j, pt));
- tmp2[0] = llround(pt[0] * scale);
- tmp2[1] = llround(pt[1] * scale);
- tmp[0] = (double)tmp2[0] / scale;
- tmp[1] = (double)tmp2[1] / scale;
+ ERR(scpr_device_scale(dev, pt, 2, tmp2));
+ ERR(scpr_device_unscale(dev, tmp2, 2, tmp));
if(tmp[0] != pt[0] || tmp[1] != pt[1]) {
res = RES_BAD_ARG;
goto error;