star-2d

Contour structuring for efficient 2D geometric queries
git clone git://git.meso-star.fr/star-2d.git
Log | Files | Refs | README | LICENSE

commit a8dd084c2b885f130b99aff9903570f99e5831db
parent 71a2fc0b49c6b592d18f6f98653a820cc2e4374c
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed,  8 Jun 2016 17:52:57 +0200

Begin the implementation of the line segment back-end

Diffstat:
Mcmake/CMakeLists.txt | 7+++++--
Msrc/s2d.h | 2+-
Asrc/s2d_buffer.h | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/s2d_line_segments.c | 234+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/s2d_line_segments.h | 134+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 483 insertions(+), 3 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -56,10 +56,13 @@ set(VERSION_PATCH 0) set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) set(S2D_FILES_SRC - s2d_device.c) + s2d_device.c + s2d_line_segments.c) set(S2D_FILES_INC_API s2d.h) set(S2D_FILES_INC - s2d_device_c.h) + s2d_buffer.h + s2d_device_c.h + s2d_line_segments.h) set(S2D_FILES_DOC COPYING.fr COPYING.en README.md) # Prepend each file in the `S2D_FILES_<SRC|INC>' list by `S2D_SOURCE_DIR' diff --git a/src/s2d.h b/src/s2d.h @@ -389,7 +389,7 @@ s2d_line_segments_setup_indexed_vertices (struct s2d_shape* shape, const unsigned nsegments, void (*get_indices) /* May be S2D_KEEP, i.e. do not update the indices */ - (const unsigned isegment, unsigned ids[3], void* ctx), + (const unsigned isegment, unsigned ids[2], void* ctx), const unsigned nverts, /* List of the shape vertex data. Must have at least an attrib with the * S2D_POSITION usage. */ diff --git a/src/s2d_buffer.h b/src/s2d_buffer.h @@ -0,0 +1,109 @@ +/* Copyright (C) |Meso|Star> 2016 (contact@meso-star.com) + * + * This software is governed by the CeCILL license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. */ + +#if !defined(BUFFER_NAME) && !defined(BUFFER_DARRAY) + +#ifndef S2D_BUFFER_H +#define S2D_BUFFER_H + +#include <rsys/mem_allocator.h> +#include <rsys/ref_count.h> + +#endif /* S2D_BUFFER_H */ +#else +/* + * Generate the buffer type with respect to the following macros: + * - BUFFER_NAME: name of the structure and prefix of the functions; + * - BUFFER_DARRAY: type of the dynamic array of the buffer; + */ +#if !defined(BUFFER_NAME) || !defined(BUFFER_DARRAY) + #error "Missing macro definition" +#endif + +#define BUFFER_FUNC__(Func) CONCAT(CONCAT(BUFFER_NAME, _), Func) +#define BUFFER_DARRAY_FUNC__(Func) CONCAT(CONCAT(BUFFER_DARRAY, _), Func) + +struct BUFFER_NAME { + BUFFER_DARRAY data; + struct mem_allocator* allocator; + ref_T ref; +}; + +/******************************************************************************* + * Helper function + ******************************************************************************/ +static INLINE void +BUFFER_FUNC__(release__)(ref_T* ref) +{ + struct BUFFER_NAME* buffer; + ASSERT(ref); + buffer = CONTAINER_OF(ref, struct BUFFER_NAME, ref); + BUFFER_DARRAY_FUNC__(release)(&buffer->data); + MEM_RM(buffer->allocator, buffer); +} + +/******************************************************************************* + * Buffer function + ******************************************************************************/ +static INLINE res_T +BUFFER_FUNC__(create) + (struct mem_allocator* allocator, + struct BUFFER_NAME** out_buffer) +{ + struct BUFFER_NAME* buffer; + ASSERT(allocator && out_buffer); + + buffer = (struct BUFFER_NAME*)MEM_CALLOC + (allocator, 1, sizeof(struct BUFFER_NAME)); + if(!buffer) return RES_MEM_ERR; + BUFFER_DARRAY_FUNC__(init)(allocator, &buffer->data); + buffer->allocator = allocator; + ref_init(&buffer->ref); + *out_buffer = buffer; + return RES_OK; +} + +static INLINE void +BUFFER_FUNC__(ref_get)(struct BUFFER_NAME* buffer) +{ + ASSERT(buffer); + ref_get(&buffer->ref); +} + +static INLINE void +BUFFER_FUNC__(ref_put)(struct BUFFER_NAME* buffer) +{ + ASSERT(buffer); + ref_put(&buffer->ref, BUFFER_FUNC__(release__)); +} + +#undef BUFFER_NAME +#undef BUFFER_DARRAY + +#endif /* !BUFFER_NAME || !BUFFER_DARRAY */ + diff --git a/src/s2d_line_segments.c b/src/s2d_line_segments.c @@ -0,0 +1,234 @@ +/* Copyright (C) |Meso|Star> 2016 (contact@meso-star.com) + * + * This software is governed by the CeCILL license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. */ + +#include "s2d_device_c.h" +#include "s2d_line_segments.h" + +#include <rsys/float2.h> + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static void +line_segments_release(ref_T* ref) +{ + struct line_segments* lines; + struct s2d_device* dev; + ASSERT(ref); + + lines = CONTAINER_OF(ref, struct line_segments, ref); + line_segments_clear(lines); + dev = lines->dev; + MEM_RM(dev->allocator, lines); + S2D(device_ref_put(dev)); +} + +/******************************************************************************* + * Local functions + ******************************************************************************/ +res_T +line_segments_create(struct s2d_device* dev, struct line_segments** out_lines) +{ + struct line_segments* lines = NULL; + res_T res = RES_OK; + ASSERT(dev && out_lines); + + lines = (struct line_segments*)MEM_CALLOC + (dev->allocator, 1, sizeof(struct line_segments)); + if(!lines) { + res = RES_MEM_ERR; + goto error; + } + ref_init(&lines->ref); + S2D(device_ref_get(dev)); + lines->dev = dev; + +exit: + *out_lines = lines; + return res; +error: + if(lines) { + line_segments_ref_put(lines); + lines = NULL; + } + goto exit; +} + +void +line_segments_ref_get(struct line_segments* lines) +{ + ASSERT(lines); + ref_get(&lines->ref); +} + +void +line_segments_ref_put(struct line_segments* lines) +{ + ASSERT(lines); + ref_put(&lines->ref, line_segments_release); +} + +void +line_segments_clear(struct line_segments* lines) +{ + size_t iattr; + ASSERT(lines); + if(lines->indices) { + index_buffer_ref_put(lines->indices); + lines->indices = NULL; + } + FOR_EACH(iattr, 0, S2D_ATTRIBS_COUNT__) { + if(lines->attribs[iattr]) { + vertex_buffer_ref_put(lines->attribs[iattr]); + lines->attribs[iattr] = NULL; + } + } + lines->resize_mask = 0; + lines->update_mask = 0; +} + +size_t +line_segments_get_nsegments(const struct line_segments* lines) +{ + size_t nids; + ASSERT(lines); + if(!lines->indices) + return 0; + nids = darray_u32_size_get(&lines->indices->data); + ASSERT(nids % 2 == 0); /* 2 vertices per segment */ + return nids / 2/* #vertices per segement */; +} + +size_t +line_segments_get_nverts(const struct line_segments* lines) +{ + size_t ncoords; + ASSERT(lines); + if(!lines->attribs[S2D_POSITION]) + return 0; + ASSERT(lines->attribs_type[S2D_POSITION] == S2D_FLOAT2); + ncoords = darray_float_size_get(&lines->attribs[S2D_POSITION]->data); + ASSERT(ncoords % 2 == 0); + return ncoords / 2/* #coords per vertices */; +} + +uint32_t* +line_segments_get_ids(struct line_segments* lines) +{ + ASSERT(lines && lines->indices); + return darray_u32_data_get(&lines->indices->data); +} + +float* +line_segments_get_pos(struct line_segments* lines) +{ + ASSERT(lines && lines->attribs[S2D_POSITION]); + ASSERT(lines->attribs_type[S2D_POSITION] == S2D_FLOAT2); + return darray_float_data_get(&lines->attribs[S2D_POSITION]->data); +} + +float* +line_segments_get_attr + (struct line_segments* lines, + const enum s2d_attrib_usage usage) +{ + ASSERT(lines && usage < S2D_ATTRIBS_COUNT__ && lines->attribs[usage]); + return darray_float_data_get(&lines->attribs[usage]->data); +} + +float +line_segments_compute_length(struct line_segments* lines) +{ + const uint32_t* ids; + const float* pos; + size_t iseg, nsegs; + float tmp[2]; + float length = 0.f; + ASSERT(lines); + + nsegs = line_segments_get_nsegments(lines); + if(!nsegs) return 0.f; + + ids = line_segments_get_ids(lines); + pos = line_segments_get_pos(lines); + + FOR_EACH(iseg, 0, nsegs) { + const size_t id = iseg * 2/*#ids per segment*/; + const float* v0 = pos + ids[id+0]*2/*#coords*/; + const float* v1 = pos + ids[id+1]*2/*#coords*/; + length += f2_len(f2_sub(tmp, v0, v1)); + } + return length; +} + +float +line_segments_compute_area + (struct line_segments* lines, + const char flip_contour) +{ + const uint32_t* ids; + const float* pos; + size_t iseg, nsegs; + double area2 = 0.f; + ASSERT(lines); + + nsegs = line_segments_get_nsegments(lines); + if(!nsegs) return 0.f; + + ids = line_segments_get_ids(lines); + pos = line_segments_get_pos(lines); + + /* Build a triangle whose base is the contour segment and its appex is the + * origin. Then compute the area of the triangle and add or sub it from the + * overall area whether the normal point toward or backward the appex */ + FOR_EACH(iseg, 0, nsegs) { + const size_t id = iseg * 2/*#ids per segment*/; + const float* v0 = pos + ids[id+0]*2/*#coords*/; + const float* v1 = pos + ids[id+1]*2/*#coords*/; + double tmp; + float dx, dy, N[2], C; + + dx = v1[0] - v0[0]; + dy = v1[1] - v0[1]; + + if(flip_contour) { + N[0] = -dy; + N[1] = dx; + } else { + N[0] = dy; + N[1] = -dx; + } + C = -f2_dot(N, v0); /* N.v0 + C = 0 */ + + tmp = v0[0]*v1[1] - v0[1]*v1[0]; /* Cross product */ + tmp = sqrt(tmp*tmp); /* 2 * area of the triangle */ + area2 += C > 0 ? tmp : -tmp; + } + return (float)(area2 * 0.5); +} + diff --git a/src/s2d_line_segments.h b/src/s2d_line_segments.h @@ -0,0 +1,134 @@ +/* Copyright (C) |Meso|Star> 2016 (contact@meso-star.com) + * + * This software is governed by the CeCILL license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. */ + +#ifndef S2D_LINE_SEGMENTS_H +#define S2D_LINE_SEGMENTS_H + +#include "s2d.h" + +#include "s2d_buffer.h" + +#include <rsys/dynamic_array_u32.h> +#include <rsys/dynamic_array_float.h> +#include <rsys/ref_count.h> + +/* Generate the index buffer data type */ +#define BUFFER_NAME index_buffer +#define BUFFER_DARRAY darray_u32 +#include "s2d_buffer.h" + +/* Generate the vertex buffer data type */ +#define BUFFER_NAME vertex_buffer +#define BUFFER_DARRAY darray_float +#include "s2d_buffer.h" + +enum buffer_type { + INDEX_BUFFER = BIT(0), + VERTEX_BUFFER = BIT(1) +}; + +struct line_segments { /* Segmented contour */ + struct index_buffer* indices; + struct vertex_buffer* attribs[S2D_ATTRIBS_COUNT__]; + enum s2d_type attribs_type[S2D_ATTRIBS_COUNT__]; + + int resize_mask; /* Combination of buffer_type */ + int update_mask; /* Combination of buffer_type */ + struct s2d_device* dev; + ref_T ref; +}; + +extern LOCAL_SYM res_T +line_segments_create + (struct s2d_device* dev, + struct line_segments* lines); + +extern LOCAL_SYM void +line_segments_ref_get + (struct line_segments* lines); + +extern LOCAL_SYM void +line_segments_ref_put + (struct line_segments* lines); + +extern LOCAL_SYM void +line_segments_clear + (struct line_segments* lines); + +extern LOCAL_SYM size_t +line_segments_get_nsegments + (const struct line_segments* lines); + +extern LOCAL_SYM size_t +line_segments_get_nverts + (const struct line_segments* lines); + +extern LOCAL_SYM uint32_t* +line_segments_get_ids + (struct line_segments* lines); + +extern LOCAL_SYM float* +line_segments_get_pos + (struct line_segments* lines); + +extern LOCAL_SYM float* +line_segments_get_attr + (struct line_segments* lines); + +extern LOCAL_SYM float +line_segments_compute_length + (struct line_segments* lines); + +extern LOCAL_SYM float +line_segments_compute_area + (struct line_segments* lines, + const char flip_contour); + +extern LOCAL_SYM float +line_segments_setup_indexed_vertices + (struct line_segments* lines, + const unsigned ntris, + void (*get_indices)(const unsigned isegment, unsigned ids[2], void* ctx), + const unsigned nverts, + struct s2d_vertex_data attribs[], + const unsigned nattribs, + void* data); + +extern LOCAL_SYM void +line_segments_compute_aabb + (struct line_segments* lines, + float lower[2], + float upper[2]); + +extern LOCAL_SYM void +line_segments_copy_indexed_vertices + (const struct line_segments* src, + struct line_segments* dst); + +#endif /* S2D_LINE_SEGMENTS_H */ +