commit 0f0da4bebf1c223b64c2f2cc9f310009a3d7db11
parent dfedf8d7d07cf1e99f54f7514d07b54a5a9496d8
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Fri, 21 Apr 2023 09:33:20 +0200
Introduce ref counting for geometries
Code simplification and new API calls related to STL output of geometries
Diffstat:
9 files changed, 547 insertions(+), 424 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -38,7 +38,7 @@ include_directories(${GMSH_INCLUDE_DIR} ${RSys_INCLUDE_DIR})
################################################################################
set(VERSION_MAJOR 0)
set(VERSION_MINOR 1)
-set(VERSION_PATCH 0)
+set(VERSION_PATCH 1)
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
set(SCAD_FILES_SRC
diff --git a/src/scad.c b/src/scad.c
@@ -23,26 +23,37 @@
#include <rsys/cstr.h>
#include <rsys/rsys.h>
#include <rsys/str.h>
+#include <rsys/dynamic_array_int.h>
+#include <rsys/dynamic_array_double.h>
#include <rsys/double3.h>
#include <rsys/float3.h>
+#include <star/sstl.h>
+
#include <stdio.h>
+#include <stdlib.h>
#define OKP(Expr) if((Expr) < 0) { res=RES_IO_ERR; goto error; }
+static int
+int_compare(const void *a_, const void *b_) {
+ const int *a = (const int *)a_;
+ const int *b = (const int *)b_;
+ ASSERT(a && b);
+ return (*a > *b) - (*a < *b);
+}
+
static res_T
write_ascii_stl
(const char* filename,
- const unsigned trg_count,
- double* const* coord,
- const size_t* coord_n)
+ double* coord,
+ const size_t coord_n)
{
res_T res = RES_OK;
size_t i;
FILE* stl_file = NULL;
- unsigned cpt;
- ASSERT(filename && coord && coord_n);
+ ASSERT(filename && (coord || coord_n == 0) && (coord_n % 9 == 0));
stl_file = fopen(filename, "w");
if(!stl_file) {
@@ -52,39 +63,32 @@ write_ascii_stl
OKP(fprintf(stl_file, "solid %s\n", filename));
- i = 0;
- cpt = 0;
- while(cpt < trg_count) {
- size_t j;
- for(j = 0; j < coord_n[i]; j += 9) {
- int k;
- double n[3] = { 0,0,0 }, zero[3] = { 0,0,0 };
- double vtx[3][3];
- double tmp[3], edge1[3], edge2[3];;
- d3_set(vtx[0], coord[i]+j+0);
- d3_set(vtx[1], coord[i]+j+3);
- d3_set(vtx[2], coord[i]+j+6);
- d3_sub(edge1, vtx[1], vtx[0]);
- d3_sub(edge2, vtx[2], vtx[0]);
- d3_cross(tmp, edge1, edge2);
- if(d3_eq(tmp, zero)) {
- log_error(get_device(), "Error: nul triangle in exported geometry.\n");
- res = RES_BAD_ARG;
- goto error;
- }
- d3_normalize(n, tmp);
-
- OKP(fprintf(stl_file, " facet normal %g %g %g\n", SPLIT3(n)));
- OKP(fprintf(stl_file, " outer loop\n"));
- for(k = 0; k < 3; k++) {
- OKP(fprintf(stl_file, " vertex %.16g %.16g %.16g\n", SPLIT3(vtx[k])));
- }
- OKP(fprintf(stl_file, " endloop\n"));
- OKP(fprintf(stl_file, " endfacet\n"));
+ /* trg_count triangles split in coord_n blocs */
+ for(i = 0; i < coord_n; i += 9) {
+ int k;
+ double n[3] = { 0,0,0 }, zero[3] = { 0,0,0 };
+ double vtx[3][3];
+ double tmp[3], edge1[3], edge2[3];;
+ d3_set(vtx[0], coord+i+0);
+ d3_set(vtx[1], coord+i+3);
+ d3_set(vtx[2], coord+i+6);
+ d3_sub(edge1, vtx[1], vtx[0]);
+ d3_sub(edge2, vtx[2], vtx[0]);
+ d3_cross(tmp, edge1, edge2);
+ if(d3_eq(tmp, zero)) {
+ log_error(get_device(), "Error: nul triangle in exported geometry.\n");
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ d3_normalize(n, tmp);
- cpt++;
+ OKP(fprintf(stl_file, " facet normal %g %g %g\n", SPLIT3(n)));
+ OKP(fprintf(stl_file, " outer loop\n"));
+ for(k = 0; k < 3; k++) {
+ OKP(fprintf(stl_file, " vertex %.16g %.16g %.16g\n", SPLIT3(vtx[k])));
}
- i++;
+ OKP(fprintf(stl_file, " endloop\n"));
+ OKP(fprintf(stl_file, " endfacet\n"));
}
OKP(fprintf(stl_file, "endsolid \n"));
@@ -100,17 +104,16 @@ error:
static res_T
write_binary_stl
(const char* filename,
- const unsigned trg_count,
- double* const* coord,
- const size_t* coord_n)
+ double* coord,
+ const size_t coord_n)
{
res_T res = RES_OK;
size_t i;
+ unsigned trg_count;
char header[80] = "Binary STL";
FILE* stl_file = NULL;
- unsigned cpt;
- ASSERT(filename && coord && coord_n);
+ ASSERT(filename && (coord || coord_n == 0) && (coord_n % 9 == 0));
stl_file = fopen(filename, "wb");
if(!stl_file) {
@@ -123,37 +126,32 @@ write_binary_stl
goto error;
}
+ trg_count = (unsigned)coord_n / 9;
if(1 != fwrite(&trg_count, 4, 1, stl_file)) {
res = RES_IO_ERR;
goto error;
}
- i = 0;
- cpt = 0;
- while(cpt < trg_count) {
- size_t j;
- for(j = 0; j < coord_n[i]; j += 9) {
- struct {
- float n[3];
- float vrtx[3][3];
- unsigned short attrib;
- } trg;
- float tmp[3], edge1[3], edge2[3];;
- f3_set_d3(trg.vrtx[0], coord[i]+j+0);
- f3_set_d3(trg.vrtx[1], coord[i]+j+3);
- f3_set_d3(trg.vrtx[2], coord[i]+j+6);
- f3_sub(edge1, trg.vrtx[1], trg.vrtx[0]);
- f3_sub(edge2, trg.vrtx[2], trg.vrtx[0]);
- f3_cross(tmp, edge1, edge2);
- f3_normalize(trg.n, tmp);
- trg.attrib = 0;
- if(1 != fwrite(&trg, 50, 1, stl_file)) {
- res = RES_IO_ERR;
- goto error;
- }
- cpt++;
+ /* trg_count triangles split in coord_n blocs */
+ for(i = 0; i < coord_n; i += 9) {
+ struct {
+ float n[3];
+ float vrtx[3][3];
+ unsigned short attrib;
+ } trg;
+ float tmp[3], edge1[3], edge2[3];;
+ f3_set_d3(trg.vrtx[0], coord+i+0);
+ f3_set_d3(trg.vrtx[1], coord+i+3);
+ f3_set_d3(trg.vrtx[2], coord+i+6);
+ f3_sub(edge1, trg.vrtx[1], trg.vrtx[0]);
+ f3_sub(edge2, trg.vrtx[2], trg.vrtx[0]);
+ f3_cross(tmp, edge1, edge2);
+ f3_normalize(trg.n, tmp);
+ trg.attrib = 0;
+ if(1 != fwrite(&trg, 50, 1, stl_file)) {
+ res = RES_IO_ERR;
+ goto error;
}
- i++;
}
exit:
@@ -165,17 +163,60 @@ error:
goto exit;
}
-static res_T
-write_stl
- (const char* filename,
- const unsigned trg_count,
- double* const* coord,
- const size_t* coord_n,
- const int binary)
+/* Accumulate tags of geometry in tags */
+res_T
+get_2d_tags
+ (struct scad_geometry* geometry,
+ struct darray_int* tags)
{
- ASSERT(filename && coord && coord_n);
- if(binary) return write_binary_stl(filename, trg_count, coord, coord_n);
- else return write_ascii_stl(filename, trg_count, coord, coord_n);
+ int* dimTags_to_free = NULL;
+ size_t i;
+ int ierr = 0;
+ int* data;
+ size_t sz;
+ res_T res = RES_OK;
+
+ ASSERT(geometry && tags);
+
+ sz = geometry->gmsh_dimTags_n;
+ data = geometry->gmsh_dimTags;
+ ASSERT(sz > 0 && sz % 2 == 0);
+
+ for(i = 0; i < sz; i += 2) {
+ int dim = data[i];
+ int tag = data[i+1];
+ size_t j;
+ if(dim == 3) {
+ int* face_dimTags = NULL;
+ size_t face_dimTags_n, count;
+ gmshModelMeshSetOutwardOrientation(tag, &ierr);
+ ERR(gmsh_err_to_res_T(ierr));
+ /* Get 2d components of the 3d object */
+ gmshModelGetBoundary(data+i, 2, &face_dimTags, &face_dimTags_n, 1, 0, 0, &ierr);
+ dimTags_to_free = face_dimTags;
+ ERR(gmsh_err_to_res_T(ierr));
+ ASSERT(face_dimTags_n % 2 == 0);
+ /* copy tags in the output */
+ count = darray_int_size_get(tags);
+ ERR(darray_int_reserve(tags, count + face_dimTags_n/2));
+ for(j = 0; j < face_dimTags_n; j += 2) {
+ ASSERT(face_dimTags[j] == 2); /* dim == 2 */
+ ERR(darray_int_push_back(tags, &face_dimTags[j+1]));
+ }
+ gmshFree(dimTags_to_free); dimTags_to_free = NULL;
+ }
+ else if(dim == 2) {
+ ERR(darray_int_push_back(tags, &data[i+1]));
+ } else {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ }
+exit:
+ gmshFree(dimTags_to_free);
+ return res;
+error:
+ goto exit;
}
/******************************************************************************
@@ -261,241 +302,265 @@ error:
}
res_T
-scad_stl_export
+scad_stl_get_data
(struct scad_geometry* geometry,
- const char* prefix,
const int reverse,
- const int binary)
+ struct darray_double* triangles)
{
- struct str filename;
- int* dimTags_to_free = NULL;
- int* faces_dimTags = NULL;
- size_t faces_dimTags_n;
- size_t** nodeTags = NULL;
- size_t* nodeTags_n = NULL;
- double** coord = NULL;
- size_t* coord_n = NULL;
- double** pCoord = NULL;
- size_t* pCoord_n = NULL;
- size_t i, tcount;
- int dim_ctrl;
+ return scad_stl_get_data_partial(geometry, NULL, 0, reverse, triangles);
+}
+
+res_T
+scad_stl_get_data_partial
+ (struct scad_geometry* geometry,
+ struct scad_geometry** dont,
+ const size_t dont_count,
+ const int reverse,
+ struct darray_double* triangles)
+{
+ size_t* nodeTags = NULL;
+ double* coord = NULL;
+ double* pCoord = NULL;
+ size_t i, tcount, sz, dsz = 0;
int ierr = 0;
- int* data;
- size_t sz;
- int str_initialized = 0;
+ int *data, *ddata = NULL;
struct scad_device* dev = get_device();
struct mem_allocator* allocator = NULL;
+ struct darray_int tags;
+ struct darray_int dtags;
+ int tags_initialized = 0;
res_T res = RES_OK;
- if(!geometry) {
+ if(!geometry || !triangles) {
res = RES_BAD_ARG;
goto error;
}
ERR(check_device(FUNC_NAME));
- sz = geometry->gmsh_dimTags_n;
- data = geometry->gmsh_dimTags;
- ASSERT(sz > 0 && sz % 2 == 0);
-
allocator = dev->allocator;
- str_init(allocator, &filename);
- str_initialized = 1;
- if(prefix) {
- ERR(str_set(&filename, prefix));
+ darray_int_init(allocator, &tags);
+ darray_int_init(allocator, &dtags);
+ tags_initialized = 1;
+
+ /* Get 2d tags */
+ if(reverse) {
+ gmshModelMeshReverse(geometry->gmsh_dimTags, geometry->gmsh_dimTags_n, &ierr);
+ ERR(get_2d_tags(geometry, &tags));
} else {
- if(str_len(&geometry->name) == 0) {
- res = RES_BAD_ARG;
- goto error;
- }
- ERR(str_copy(&filename, &geometry->name));
+ ERR(get_2d_tags(geometry, &tags));
}
- ERR(str_append(&filename, ".stl"));
-
- dim_ctrl = data[0];
- if(dim_ctrl == 3) { /* geometry is 3D */
- ERR(scad_synchronize());
- ERR(gmsh_err_to_res_T(ierr));
-
- /* TODO: use options to set inward/outward orientation???
- * Is it even needed???? */
- for(i = 0; i < sz/2; i++) {
- ASSERT(data[2*i] == dim_ctrl); /* Only 3D tags */
- gmshModelMeshSetOutwardOrientation(data[2*i+1], &ierr);
- ERR(gmsh_err_to_res_T(ierr));
- }
- if (reverse) gmshModelMeshReverse(data, sz, &ierr);
- ERR(gmsh_err_to_res_T(ierr));
+ sz = darray_int_size_get(&tags);
+ data = darray_int_data_get(&tags);
- /* Get tags to be written (boundary of geometry) */
- gmshModelGetBoundary(data, sz, &faces_dimTags, &faces_dimTags_n, 1, 0, 0, &ierr);
- dimTags_to_free = faces_dimTags;
- ERR(gmsh_err_to_res_T(ierr));
- ASSERT(faces_dimTags_n % 2 == 0);
- } else { /* Geometry is 2D */
- /* Tags to be written are the tags of the 2D object itself */
- faces_dimTags_n = sz;
- faces_dimTags = data;
- for(i = 0; i < sz/2; i++) {
- ASSERT(data[2*i] == dim_ctrl); /* Only 3D tags */
+ if(dont) {
+ for(i = 0; i < dont_count; i++) {
+ ERR(get_2d_tags(dont[i], &dtags));
}
- if (reverse) gmshModelMeshReverse(data, sz, &ierr);
- ERR(gmsh_err_to_res_T(ierr));
- }
-
- /* Allocate room for arrays */
- nodeTags = MEM_CALLOC(allocator, faces_dimTags_n/2, sizeof(*nodeTags));
- nodeTags_n = MEM_CALLOC(allocator, faces_dimTags_n/2, sizeof(*nodeTags_n));
- coord = MEM_CALLOC(allocator, faces_dimTags_n/2, sizeof(*coord));
- coord_n = MEM_CALLOC(allocator, faces_dimTags_n/2, sizeof(*coord_n));
- pCoord = MEM_CALLOC(allocator, faces_dimTags_n/2, sizeof(*pCoord));
- pCoord_n = MEM_CALLOC(allocator, faces_dimTags_n/2, sizeof(*pCoord_n));
- if(!nodeTags || !nodeTags_n || !coord || !coord_n || !pCoord || !pCoord_n) {
- res = RES_MEM_ERR;
- goto error;
+ dsz = darray_int_size_get(&dtags);
+ ddata = darray_int_data_get(&dtags);
+ /* Sort ddata tags to enable bsearch */
+ qsort(ddata, dsz, sizeof(*ddata), int_compare);
}
+ /* Collect triangles */
tcount = 0;
- for(i = 0; i < faces_dimTags_n/2; i++) {
- /* type = 2: 3-node triangles (see src/common/GmshDefines.h) */
- gmshModelMeshGetNodesByElementType(2, nodeTags+i, nodeTags_n+i,
- coord+i, coord_n+i, pCoord+i, pCoord_n+i, faces_dimTags[2*i+1], 0, &ierr);
+ for(i = 0; i < sz; i++) {
+ size_t count, j, coord_n, pCoord_n, nodeTags_n;
+ const int type = 2; /* 3-node triangles (see src/common/GmshDefines.h) */
+ if(bsearch(data+i, ddata, dsz, sizeof(*ddata), int_compare)) {
+ /* this tag is part of the dont list: don't collect */
+ continue;
+ }
+ gmshModelMeshGetNodesByElementType(type, &nodeTags, &nodeTags_n,
+ &coord, &coord_n, &pCoord, &pCoord_n, data[i], 0, &ierr);
ERR(gmsh_err_to_res_T(ierr));
- ASSERT(nodeTags_n[i] % 3 == 0);
- ASSERT(coord_n[i] == nodeTags_n[i] * 3);
- tcount += coord_n[i];
+ ASSERT(nodeTags_n % 3 == 0);
+ ASSERT(coord_n == nodeTags_n * 3);
+ tcount += coord_n;
+ count = darray_double_size_get(triangles);
+ ERR(darray_double_reserve(triangles, count + coord_n));
+ for(j = 0; j < coord_n; j++) {
+ ERR(darray_double_push_back(triangles, &coord[j]));
+ }
+ gmshFree(nodeTags); nodeTags = NULL;
+ gmshFree(coord); coord = NULL;
+ gmshFree(pCoord); pCoord = NULL;
}
+ ASSERT(tcount == darray_double_size_get(triangles));
tcount /= 9;
- ASSERT(tcount <= UINT_MAX);
-
- ERR(write_stl(str_cget(&filename), (unsigned)tcount, coord, coord_n, binary));
exit:
if(!allocator) {
/* Early error, nothing was allocated */
return res;
}
- if(str_initialized) str_release(&filename);
- gmshFree(dimTags_to_free);
- if(nodeTags) {
- for(i = 0; i < faces_dimTags_n/2; i++) gmshFree(nodeTags[i]);
- MEM_RM(allocator, nodeTags);
- }
- MEM_RM(allocator, nodeTags_n);
- if(coord) {
- for(i = 0; i < faces_dimTags_n/2; i++) gmshFree(coord[i]);
- MEM_RM(allocator, coord);
+ if(tags_initialized) {
+ darray_int_release(&tags);
+ darray_int_release(&dtags);
}
- MEM_RM(allocator, coord_n);
- if(pCoord) {
- for(i = 0; i < faces_dimTags_n/2; i++) gmshFree(pCoord[i]);
- MEM_RM(allocator, pCoord);
- }
- MEM_RM(allocator, pCoord_n);
+ gmshFree(nodeTags);
+ gmshFree(coord);
+ gmshFree(pCoord);
return res;
error:
if(dev) {
- log_error(dev, "%s: could not export to STL -- %s\n",
+ log_error(dev, "%s: could not get STL data -- %s\n",
FUNC_NAME, res_to_cstr(res));
}
goto exit;
}
res_T
-scad_stl_export_split
+scad_stl_data_write
+ (struct darray_double* triangles,
+ const char* filename,
+ const int binary)
+{
+ res_T res = RES_OK;
+ size_t coord_n;
+ double* coord;
+
+ if(!triangles || !filename) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ coord_n = darray_double_size_get(triangles);
+ if(coord_n % 9) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ coord = darray_double_data_get(triangles);
+
+ if(binary) ERR( write_binary_stl(filename, coord, coord_n));
+ else ERR(write_ascii_stl(filename, coord, coord_n));
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+res_T
+scad_stl_export
(struct scad_geometry* geometry,
const char* prefix,
- const int binary) /* FIXME: unused as we use gmshWrite */
+ const int reverse,
+ const int binary)
{
- struct str filename_root;
- struct str filename;
- int* tagout = NULL;
- size_t tagoutn, i;
- int dimtag[2];
- int group;
- int ierr = 0;
- int* data;
- size_t sz;
- int str_initialized = 0;
res_T res = RES_OK;
+ struct darray_double trg;
+ struct scad_device* dev = get_device();
+ struct str filename;
+ int initialized = 0;
- (void)binary;
+ if(!geometry || (!prefix && str_is_empty(&geometry->name))) {
+ res= RES_BAD_ARG;
+ goto error;
+ }
+
+ ERR(check_device(FUNC_NAME));
+
+ darray_double_init(dev->allocator, &trg);
+ str_init(dev->allocator, &filename);
+ initialized = 1;
+ if(prefix) {
+ ERR(str_set(&filename, prefix));
+ } else {
+ ERR(str_copy(&filename, &geometry->name));
+ }
+ ERR(str_append(&filename, ".stl"));
+ ERR(scad_stl_get_data(geometry, reverse, &trg));
+ ERR(scad_stl_data_write(&trg, str_cget(&filename), binary));
+
+exit:
+ if(initialized) {
+ darray_double_release(&trg);
+ str_release(&filename);
+ }
+ return res;
+error:
+ goto exit;
+}
+
+res_T
+scad_stl_export_partial
+ (struct scad_geometry* geometry,
+ struct scad_geometry** dont,
+ const size_t dont_count,
+ const char* prefix,
+ const int reverse,
+ const int binary)
+{
+ res_T res = RES_OK;
+ struct darray_double trg;
+ struct scad_device* dev = get_device();
+ struct str filename;
+ int initialized = 0;
if(!geometry) {
- res = RES_BAD_ARG;
+ res= RES_BAD_ARG;
goto error;
}
ERR(check_device(FUNC_NAME));
- sz = geometry->gmsh_dimTags_n;
- data = geometry->gmsh_dimTags;
- ASSERT(sz % 2 == 0);
-
- str_init(get_device()->allocator, &filename_root);
- str_init(get_device()->allocator, &filename);
- str_initialized = 1;
+ darray_double_init(dev->allocator, &trg);
+ str_init(dev->allocator, &filename);
+ initialized = 1;
if(prefix) {
- ERR(str_set(&filename_root, prefix));
+ ERR(str_set(&filename, prefix));
} else {
if(str_len(&geometry->name) == 0) {
res = RES_BAD_ARG;
goto error;
}
- ERR(str_copy(&filename_root, &geometry->name));
+ ERR(str_copy(&filename, &geometry->name));
}
- ERR(str_append(&filename_root, "_"));
-
- if(data[0] == 2) {
- FOR_EACH(i, 0, sz/2) {
- ASSERT(data[2*i] == 2);
- /* When upgrading to gmsh 4.11 the additional arg. name cannot be NULL;
- * use "" instead */
- group = gmshModelAddPhysicalGroup(2, &data[2*i+1], 1, -1, &ierr);
- ERR(gmsh_err_to_res_T(ierr));
- ERR(str_copy(&filename, &filename_root));
- ERR(str_append_printf(&filename, "%lu.stl", (unsigned long)i));
- gmshWrite(str_cget(&filename), &ierr);
- ERR(gmsh_err_to_res_T(ierr));
+ ERR(str_append(&filename, ".stl"));
+ ERR(scad_stl_get_data_partial(geometry, dont, dont_count, reverse, &trg));
+ ERR(scad_stl_data_write(&trg, str_cget(&filename), binary));
- dimtag[0]=2;
- dimtag[1]=group;
- gmshModelRemovePhysicalGroups(dimtag, 2, &ierr);
- ERR(gmsh_err_to_res_T(ierr));
- }
- } else {
- FOR_EACH(i, 0, sz/2) {
- ASSERT(data[2*i] == 3);
- gmshModelMeshSetOutwardOrientation(data[2*i+1], &ierr);
- ERR(gmsh_err_to_res_T(ierr));
- }
+exit:
+ if(initialized) {
+ darray_double_release(&trg);
+ str_release(&filename);
+ }
+ return res;
+error:
+ goto exit;
+}
- gmshModelGetBoundary(data, sz, &tagout, &tagoutn, 1, 0, 0, &ierr);
- ERR(gmsh_err_to_res_T(ierr));
+res_T
+scad_stl_export_split
+ (struct scad_geometry* geometry,
+ const char* prefix,
+ const int reverse,
+ const int binary)
+{
+ size_t i;
+ struct scad_geometry** parts = NULL;
+ struct scad_device* dev = get_device();
+ size_t count;
+ res_T res = RES_OK;
+ (void)binary;
- FOR_EACH(i, 0, tagoutn/2){
- /* When upgrading to gmsh 4.11 the additional arg. name cannot be NULL;
- * use "" instead */
- group = gmshModelAddPhysicalGroup(2, tagout + 2*i+1, 1, -1, &ierr);
- ERR(gmsh_err_to_res_T(ierr));
- ERR(str_copy(&filename, &filename_root));
- ERR(str_append_printf(&filename, "%lu.stl", (unsigned long)i));
- gmshWrite(str_cget(&filename), &ierr);
- ERR(gmsh_err_to_res_T(ierr));
+ if(!geometry || (!prefix && str_is_empty(&geometry->name))) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
- dimtag[0]=2;
- dimtag[1]=group;
- gmshModelRemovePhysicalGroups(dimtag, 2, &ierr);
- ERR(gmsh_err_to_res_T(ierr));
- }
+ ERR(check_device(FUNC_NAME));
+
+ ERR(scad_geometry_explode(geometry, prefix, &parts, &count));
+ ASSERT(count*2 == geometry->gmsh_dimTags_n);
+ for(i = 0; i < count; i++) {
+ ERR(scad_stl_export(parts[i], NULL, reverse, binary));
}
exit:
- if(str_initialized) {
- str_release(&filename_root);
- str_release(&filename);
- }
- gmshFree(tagout);
+ MEM_RM(dev->allocator, parts);
return res;
error:
goto exit;
diff --git a/src/scad.h b/src/scad.h
@@ -40,6 +40,7 @@
struct mem_allocator;
struct logger;
struct str;
+struct darray_double;
/* Forward declaration of scad opaque data types */
struct scad_geometry; /* Wrapping of dimTags gmsh description */
@@ -158,7 +159,11 @@ scad_synchronize
******************************************************************************/
SCAD_API res_T
-scad_geometry_delete
+scad_geometry_ref_get
+ (struct scad_geometry* geom);
+
+SCAD_API res_T
+scad_geometry_ref_put
(struct scad_geometry* geom);
SCAD_API res_T
@@ -368,7 +373,7 @@ scad_geometry_rotate
const double dir[3],
const double angle);
-/* Extrude the geometry `geom' using a translation along (`dx', `dy', `dz').*/
+/* Extrude the geometry `geom' using a translation along (`dx', `dy', `dz'). */
SCAD_API res_T
scad_geometry_extrude
(const struct scad_geometry* geom,
@@ -376,26 +381,29 @@ scad_geometry_extrude
const double dxdydz[3],
struct scad_geometry** out_geometry);
-/* Return a list of geometries which form the geometry geom */
+/* Return a list of geometries which form the geometry `geom'.
+ * Note that `out_geometries' is allocated using the allocator provided when
+ * initializing star-cad and should be freed accordingly. */
SCAD_API res_T
scad_geometry_explode
(const struct scad_geometry* geom,
const char* prefix_name, /* Can be NULL */
- struct scad_geometry*** out_geometry,
+ struct scad_geometry*** out_geometries,
size_t* out_geometry_n);
-/* Import a step model (`filename'). The imported geometries are recorded in
- * `out_geometry'.
- * Note that `out_geometry' is allocated using the allocator provided when
+/* Import a step model from file `filename'. The imported geometries are
+ * recorded in `out_geometries'.
+ * Note that `out_geometries' is allocated using the allocator provided when
* initializing star-cad and should be freed accordingly. */
SCAD_API res_T
scad_step_import
(const char* filename, /* name of step file */
const char* name, /* Can be NULL */
- struct scad_geometry*** out_geometry,
+ struct scad_geometry*** out_geometries,
size_t* out_geometry_n);
/* Export the geometry `geom' to an STL file.
+ * In order to get a mesh, one has to call scad_scene_mesh before calling this.
* If `prefix' is provided it is used to name the file (just adding .stl),
* otherwise the geometry name is used instead (and it is an error if neither
* prefix nor the geometry name are defined). The file format is either binary
@@ -407,12 +415,49 @@ scad_stl_export
const int reverse, /* set `1' to reverse mesh */
const int binary); /* File format */
+/* Same as previous, but geometries that are part of `exclude' is not exported */
+SCAD_API res_T
+scad_stl_export_partial
+ (struct scad_geometry* geometry,
+ struct scad_geometry** exclude,
+ const size_t exclude_count,
+ const char* prefix,
+ const int reverse,
+ const int binary);
+
+/* Export the geometry `geom' in as many files than its count. */
SCAD_API res_T
scad_stl_export_split
(struct scad_geometry* geom,
const char* prefix, /* Can be NULL if geometry was named: use geometry name */
+ const int reverse, /* set `1' to reverse mesh */
const int binary); /* File format */
+/* Get the mesh of the geometry `geom' into a darray_double, each triangle
+ * described * by 9 doubles in a STL way.
+ * In order to get a mesh, one has to call scad_scene_mesh before calling this. */
+SCAD_API res_T
+scad_stl_get_data
+ (struct scad_geometry* geom,
+ const int reverse, /* set `1' to reverse mesh */
+ struct darray_double* triangles); /* Can contain some triangles already */
+
+/* Same as previous, but geometries that are part of `exclude' is not collected */
+SCAD_API res_T
+scad_stl_get_data_partial
+ (struct scad_geometry* geometry,
+ struct scad_geometry** exclude,
+ const size_t exclude_count,
+ const int reverse,
+ struct darray_double* triangles); /* Can contain some triangles already */
+
+/* Write the mesh the same way stl_export do, using data as returned by
+ * stl_get_data[_partial] */
+SCAD_API res_T
+scad_stl_data_write
+ (struct darray_double* triangles,
+ const char* filename,
+ const int binary);
SCAD_API res_T
scad_scene_write
diff --git a/src/scad_c.h b/src/scad_c.h
@@ -18,6 +18,9 @@
#include <rsys/rsys.h>
+struct scad_geometry;
+struct darray_int;
+
#define ERR(Expr) if((res = (Expr)) != RES_OK) goto error; else (void)0
static INLINE res_T
@@ -33,4 +36,9 @@ gmsh_err_to_res_T(const int ierr)
return res;
}
+res_T
+get_2d_tags
+ (struct scad_geometry* geometry,
+ struct darray_int* tags);
+
#endif
diff --git a/src/scad_device.c b/src/scad_device.c
@@ -45,6 +45,8 @@ device_release(struct scad_device* dev)
empty = htable_geometries_is_empty(&dev->allgeom);
log_type = empty ? LOG_OUTPUT : LOG_WARNING;
log = (option == Scad_log_all) || (!empty && option == Scad_log_only_undeleted);
+ dev->log = log;
+ dev->log_type = log_type;
/* Duplicate the htable we iterate on as dev->allgeom will be altered during
* the process (through calls to geometry_release) */
@@ -57,7 +59,7 @@ device_release(struct scad_device* dev)
}
while(!htable_geometries_iterator_eq(&it, &end)) {
struct scad_geometry* geom = *htable_geometries_iterator_key_get(&it);
- CHK(RES_OK == geometry_release(log, log_type, geom));
+ SCAD(geometry_ref_put(geom));
htable_geometries_iterator_next(&it);
}
htable_names_release(&dev->geometry_names);
@@ -315,6 +317,9 @@ scad_initialize
g_device->allocator = allocator;
g_device->need_synchro = g_device->options.Misc.DebugOpenCascadeSync;
g_device->verbose = verbose;
+ g_device->log_type = LOG_OUTPUT;
+ g_device->log
+ = (g_device->options.Misc.LogOpenCascadeTagsRefCounting== Scad_log_all);
htable_names_init(allocator, &g_device->geometry_names);
htable_geometries_init(allocator, &g_device->allgeom);
htable_tags2geom_init(allocator, &g_device->tags2geom[0]);
diff --git a/src/scad_device.h b/src/scad_device.h
@@ -73,6 +73,9 @@ struct scad_device {
int need_synchro;
ref_T ref;
+ /* Used only when releasing the geometry */
+ int log;
+ enum log_type log_type;
};
/*******************************************************************************
diff --git a/src/scad_geometry.c b/src/scad_geometry.c
@@ -43,6 +43,8 @@
#define HTABLE_DATA size_t
#include <rsys/hash_table.h>
+#include <limits.h>
+
/*******************************************************************************
* Utility functions
******************************************************************************/
@@ -105,6 +107,32 @@ error:
goto exit;
}
+static int
+mixed_dim_err_msg
+ (const char* name, /* Can be NULL */
+ const char* op,
+ struct scad_geometry** geometries,
+ const size_t geometries_count,
+ int* dim)
+{
+ size_t i, j;
+ struct scad_device* dev = get_device();
+ ASSERT(op && (geometries || geometries_count == 0) && dim);
+ for(i = 0; i < geometries_count; i++) {
+ for(j = 0; j < geometries[i]->gmsh_dimTags_n; j += 2) {
+ int d = geometries[i]->gmsh_dimTags[j];
+ if(*dim == INT_MAX) *dim = d;
+ else if (*dim != d) {
+ log_error(dev,
+ "Dimension mismatch in %s operation creating '%s' geometry.\n",
+ op, (name ? name : "unamed"));
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
static res_T
scad_geometry_create
(const char* name,
@@ -115,12 +143,8 @@ scad_geometry_create
struct scad_device* dev = get_device();
struct mem_allocator* allocator = dev->allocator;
char one = 1;
- int log;
- enum scad_log_refcounting option;
ASSERT(out_geometry);
- option = dev->options.Misc.LogOpenCascadeTagsRefCounting;
- log = option == Scad_log_all;
geom = (struct scad_geometry*)MEM_CALLOC(allocator, 1, sizeof(*geom));
if(!geom) {
@@ -128,6 +152,7 @@ scad_geometry_create
goto error;
}
+ ref_init(&geom->ref);
str_init(allocator, &geom->name);
ERR(htable_geometries_set(&dev->allgeom, &geom, &one));
ERR(geom_set_name(geom, name));
@@ -138,7 +163,7 @@ end:
return res;
error:
if(geom) {
- CHK(RES_OK == geometry_release(log, LOG_OUTPUT, geom));
+ SCAD(geometry_ref_put(geom));
geom = NULL;
}
goto end;
@@ -159,7 +184,7 @@ gather_tags
struct htable_tags t2, t3;
struct htable_tags_iterator it, end;
- ASSERT((geometries || !geometries_count) && (out_dimTags || !out_dimTags_n));
+ ASSERT((geometries || !geometries_count) && out_dimTags && out_dimTags_n);
htable_tags_init(allocator, &t2);
htable_tags_init(allocator, &t3);
@@ -236,22 +261,18 @@ free_gmsh_map
/*******************************************************************************
* Local functions
******************************************************************************/
-res_T
-geometry_release
- (const int log,
- const enum log_type log_type,
- struct scad_geometry* geom)
+static void
+geometry_release(ref_T* ref)
{
+ struct scad_geometry* geom;
struct scad_device* dev = get_device();
struct mem_allocator* allocator = dev->allocator;
- res_T res = RES_OK;
size_t n;
-
- ASSERT(geom);
+ ASSERT(ref);
dev->need_synchro = 1;
-
- ERR(device_unregister_tags(log, log_type, geom));
+ geom = CONTAINER_OF(ref, struct scad_geometry, ref);
+ CHK(RES_OK == device_unregister_tags(dev->log, dev->log_type, geom));
MEM_RM(allocator, geom->gmsh_dimTags);
if(str_len(&geom->name) != 0) {
n = htable_names_erase(&dev->geometry_names, &geom->name);
@@ -260,41 +281,32 @@ geometry_release
str_release(&geom->name);
n = htable_geometries_erase(&dev->allgeom, &geom);
ASSERT(n == 1); (void)n;
+#ifndef NDEBUG
+ geom->gmsh_dimTags = (int*)0xdeadbeef;
+#endif
MEM_RM(allocator, geom);
-
-end:
- return res;
-error:
- goto end;
}
/******************************************************************************
* Exported functions
*****************************************************************************/
res_T
-scad_geometry_delete
+scad_geometry_ref_get
(struct scad_geometry* geom)
{
- res_T res = RES_OK;
- struct scad_device* dev = get_device();
- int log;
- enum scad_log_refcounting option;
-
- if(!geom) {
- res = RES_BAD_ARG;
- goto error;
- }
-
- ERR(check_device(FUNC_NAME));
- option = dev->options.Misc.LogOpenCascadeTagsRefCounting;
- log = option == Scad_log_all;
-
- CHK(RES_OK == geometry_release(log, LOG_OUTPUT, geom));
+ if(!geom) return RES_BAD_ARG;
+ ref_get(&geom->ref);
+ return RES_OK;
+}
-end:
- return res;
-error:
- goto end;
+res_T
+scad_geometry_ref_put
+ (struct scad_geometry* geom)
+{
+ if(!geom) return RES_BAD_ARG;
+ ref_put(&geom->ref, geometry_release);
+ CHK(RES_OK == check_device(FUNC_NAME));
+ return RES_OK;
}
res_T
@@ -322,20 +334,24 @@ scad_scene_clear
empty = htable_geometries_is_empty(&dev->allgeom);
log_type = empty ? LOG_OUTPUT : LOG_WARNING;
log = (option == Scad_log_all) || (!empty && option == Scad_log_only_undeleted);
- if(log) {
- logger_print(dev->logger, log_type, "Clearing scene.\n");
+ SWAP(int, dev->log, log);
+ SWAP(enum log_type, dev->log_type, log_type);
+ if(dev->log) {
+ logger_print(dev->logger, dev->log_type, "Clearing scene.\n");
if(empty) {
- logger_print(dev->logger, log_type, "scene is empty.\n");
+ logger_print(dev->logger, dev->log_type, "scene is empty.\n");
}
}
while(!htable_geometries_iterator_eq(&it, &end)) {
struct scad_geometry* geom = *htable_geometries_iterator_key_get(&it);
- CHK(RES_OK == geometry_release(log, log_type, geom));
+ ERR(scad_geometry_ref_put(geom));
htable_geometries_iterator_next(&it);
}
- if(log) {
- logger_print(dev->logger, log_type, "End clearing scene.\n");
+ if(dev->log) {
+ logger_print(dev->logger, dev->log_type, "End clearing scene.\n");
}
+ SWAP(int, log, dev->log);
+ SWAP(enum log_type, log_type, dev->log_type);
/* Ensure clear is complete (not scad-registered tags) */
gmshClear(&ierr);
@@ -518,8 +534,6 @@ scad_add_rectangle
struct scad_geometry* geom = NULL;
struct scad_device* dev = get_device();
struct mem_allocator* allocator = NULL;
- int log;
- enum scad_log_refcounting option;
if(!xyz || !dxdy || !out_geometry) {
res = RES_BAD_ARG;
@@ -528,8 +542,6 @@ scad_add_rectangle
ERR(check_device(FUNC_NAME));
allocator = dev->allocator;
- option = dev->options.Misc.LogOpenCascadeTagsRefCounting;
- log = option == Scad_log_all;
gmsh_ID = gmshModelOccAddRectangle(SPLIT3(xyz), SPLIT2(dxdy), -1, 0, &ierr);
ERR(gmsh_err_to_res_T(ierr));
@@ -552,7 +564,7 @@ exit:
return res;
error:
if(geom) {
- CHK(RES_OK == geometry_release(log, LOG_OUTPUT, geom));
+ SCAD(geometry_ref_put(geom));
geom = NULL;
}
goto exit;
@@ -570,8 +582,6 @@ scad_add_disk
struct scad_geometry* geom = NULL;
struct scad_device* dev = get_device();
struct mem_allocator* allocator = NULL;
- int log;
- enum scad_log_refcounting option;
if(!xyz || radius <= 0 || !out_geometry) {
res = RES_BAD_ARG;
@@ -580,8 +590,6 @@ scad_add_disk
ERR(check_device(FUNC_NAME));
allocator = dev->allocator;
- option = dev->options.Misc.LogOpenCascadeTagsRefCounting;
- log = option == Scad_log_all;
gmsh_ID = gmshModelOccAddDisk(SPLIT3(xyz), radius, radius, -1, &ierr);
ERR(gmsh_err_to_res_T(ierr));
@@ -604,7 +612,7 @@ exit:
return res;
error:
if(geom) {
- CHK(RES_OK == geometry_release(log, LOG_OUTPUT, geom));
+ SCAD(geometry_ref_put(geom));
geom = NULL;
}
goto exit;
@@ -628,8 +636,6 @@ scad_add_polygon
int loop;
struct scad_device* dev = get_device();
struct mem_allocator* allocator = NULL;
- int log;
- enum scad_log_refcounting option;
if(!get_position || count < 3 || !out_geometry) {
res = RES_BAD_ARG;
@@ -638,8 +644,6 @@ scad_add_polygon
ERR(check_device(FUNC_NAME));
allocator = dev->allocator;
- option = dev->options.Misc.LogOpenCascadeTagsRefCounting;
- log = option == Scad_log_all;
points = MEM_ALLOC(allocator, count * sizeof(*points));
lines = MEM_ALLOC(allocator, count * sizeof(*lines));
@@ -688,7 +692,7 @@ exit:
return res;
error:
if(geom) {
- CHK(RES_OK == geometry_release(log, LOG_OUTPUT, geom));
+ SCAD(geometry_ref_put(geom));
geom = NULL;
}
goto exit;
@@ -706,8 +710,6 @@ scad_add_box
struct scad_geometry* geom = NULL;
struct scad_device* dev = get_device();
struct mem_allocator* allocator = NULL;
- int log;
- enum scad_log_refcounting option;
if(!xyz || !dxdydz || !out_geometry) {
res = RES_BAD_ARG;
@@ -716,8 +718,6 @@ scad_add_box
ERR(check_device(FUNC_NAME));
allocator = dev->allocator;
- option = dev->options.Misc.LogOpenCascadeTagsRefCounting;
- log = option == Scad_log_all;
gmsh_ID = gmshModelOccAddBox(SPLIT3(xyz), SPLIT3(dxdydz), -1, &ierr);
ERR(gmsh_err_to_res_T(ierr));
@@ -739,7 +739,7 @@ exit:
return res;
error:
if(geom) {
- CHK(RES_OK == geometry_release(log, LOG_OUTPUT, geom));
+ SCAD(geometry_ref_put(geom));
geom = NULL;
}
goto exit;
@@ -759,8 +759,6 @@ scad_add_cylinder
struct scad_geometry* geom = NULL;
struct scad_device* dev = get_device();
struct mem_allocator* allocator = NULL;
- int log;
- enum scad_log_refcounting option;
if(!xyz || !axis || radius <= 0 || angle < 0 || angle > 2*PI || !out_geometry) {
res = RES_BAD_ARG;
@@ -769,8 +767,6 @@ scad_add_cylinder
ERR(check_device(FUNC_NAME));
allocator = dev->allocator;
- option = dev->options.Misc.LogOpenCascadeTagsRefCounting;
- log = option == Scad_log_all;
gmsh_ID = gmshModelOccAddCylinder(SPLIT3(xyz), SPLIT3(axis), radius, -1,
angle, &ierr);
@@ -793,7 +789,7 @@ exit:
return res;
error:
if(geom) {
- CHK(RES_OK == geometry_release(log, LOG_OUTPUT, geom));
+ SCAD(geometry_ref_put(geom));
geom = NULL;
}
goto exit;
@@ -811,8 +807,6 @@ scad_add_sphere
struct scad_geometry* geom = NULL;
struct scad_device* dev = get_device();
struct mem_allocator* allocator = NULL;
- int log;
- enum scad_log_refcounting option;
if(!xyz || radius <= 0 || !out_geometry) {
res = RES_BAD_ARG;
@@ -821,8 +815,6 @@ scad_add_sphere
ERR(check_device(FUNC_NAME));
allocator = dev->allocator;
- option = dev->options.Misc.LogOpenCascadeTagsRefCounting;
- log = option == Scad_log_all;
gmsh_ID =
gmshModelOccAddSphere(SPLIT3(xyz), radius, -1, -PI/2, PI/2, 2*PI, &ierr);
@@ -845,7 +837,7 @@ exit:
return res;
error:
if(geom) {
- CHK(RES_OK == geometry_release(log, LOG_OUTPUT, geom));
+ SCAD(geometry_ref_put(geom));
geom = NULL;
}
goto exit;
@@ -871,8 +863,6 @@ scad_fuse_geometries
struct scad_geometry* geom = NULL;
struct scad_device* dev = get_device();
struct mem_allocator* allocator = NULL;
- int log;
- enum scad_log_refcounting option;
if(!geometries || !geometries_count || !tools || !tools_count || !out_geometry) {
res = RES_BAD_ARG;
@@ -881,8 +871,6 @@ scad_fuse_geometries
ERR(check_device(FUNC_NAME));
allocator = dev->allocator;
- option = dev->options.Misc.LogOpenCascadeTagsRefCounting;
- log = option == Scad_log_all;
ERR(gather_tags(geometries, geometries_count, &data1, &sz1));
ERR(gather_tags(tools, tools_count, &data2, &sz2));
@@ -916,7 +904,7 @@ exit:
return res;
error:
if(geom) {
- CHK(RES_OK == geometry_release(log, LOG_OUTPUT, geom));
+ SCAD(geometry_ref_put(geom));
geom = NULL;
}
if(tagout) gmshModelOccRemove(tagout, tagoutn, 1, &ierr);
@@ -943,8 +931,6 @@ scad_cut_geometries
struct scad_geometry* geom = NULL;
struct scad_device* dev = get_device();
struct mem_allocator* allocator = NULL;
- int log;
- enum scad_log_refcounting option;
if(!geometries || !geometries_count || !tools || !tools_count || !out_geometry) {
res = RES_BAD_ARG;
@@ -953,8 +939,6 @@ scad_cut_geometries
ERR(check_device(FUNC_NAME));
allocator = dev->allocator;
- option = dev->options.Misc.LogOpenCascadeTagsRefCounting;
- log = option == Scad_log_all;
ERR(gather_tags(geometries, geometries_count, &data1, &sz1));
ERR(gather_tags(tools, tools_count, &data2, &sz2));
@@ -987,9 +971,14 @@ exit:
free_gmsh_map(map, mapnn);
return res;
error:
- if(geom) {
- CHK(RES_OK == geometry_release(log, LOG_OUTPUT, geom));
- geom = NULL;
+ if(ierr) {
+ int dim = INT_MAX;
+ if(!mixed_dim_err_msg(name, "cut", geometries, geometries_count, &dim))
+ mixed_dim_err_msg(name, "cut", tools, tools_count, &dim);
+ if(geom) {
+ SCAD(geometry_ref_put(geom));
+ geom = NULL;
+ }
}
if(tagout) gmshModelOccRemove(tagout, tagoutn, 1, &ierr);
goto exit;
@@ -1015,8 +1004,6 @@ scad_intersect_geometries
struct scad_geometry* geom = NULL;
struct scad_device* dev = get_device();
struct mem_allocator* allocator = NULL;
- int log;
- enum scad_log_refcounting option;
if(!geometries || !geometries_count || !tools || !tools_count || !out_geometry) {
res = RES_BAD_ARG;
@@ -1025,8 +1012,6 @@ scad_intersect_geometries
ERR(check_device(FUNC_NAME));
allocator = dev->allocator;
- option = dev->options.Misc.LogOpenCascadeTagsRefCounting;
- log = option == Scad_log_all;
ERR(gather_tags(geometries, geometries_count, &data1, &sz1));
ERR(gather_tags(tools, tools_count, &data2, &sz2));
@@ -1064,7 +1049,7 @@ exit:
return res;
error:
if(geom) {
- CHK(RES_OK == geometry_release(log, LOG_OUTPUT, geom));
+ SCAD(geometry_ref_put(geom));
geom = NULL;
}
if(tagout) gmshModelOccRemove(tagout, tagoutn, 1, &ierr);
@@ -1094,8 +1079,6 @@ scad_geometries_common_boundaries
struct scad_geometry* geom = NULL;
struct mem_allocator* allocator = NULL;
struct scad_device* dev = get_device();
- int log;
- enum scad_log_refcounting option;
if(!geometries || !geometries_count || !tools || !tools_count || !out_geometry) {
res = RES_BAD_ARG;
@@ -1104,8 +1087,6 @@ scad_geometries_common_boundaries
ERR(check_device(FUNC_NAME));
allocator = dev->allocator;
- option = dev->options.Misc.LogOpenCascadeTagsRefCounting;
- log = option == Scad_log_all;
ERR(gather_tags(geometries, geometries_count, &data1, &sz1));
ERR(gather_tags(tools, tools_count, &data2, &sz2));
@@ -1124,7 +1105,7 @@ scad_geometries_common_boundaries
geom->gmsh_dimTags_n = tagoutn;
if (tagoutn == 0) {
geom->gmsh_dimTags = NULL;
- } else {
+ } else {
geom->gmsh_dimTags = MEM_ALLOC(allocator, tagoutn * sizeof(*tagout));
if(!geom->gmsh_dimTags) {
res = RES_MEM_ERR;
@@ -1148,8 +1129,17 @@ exit:
free_gmsh_map(map, mapnn);
return res;
error:
+ if(ierr) {
+ int dim = INT_MAX;
+ if(!mixed_dim_err_msg(name, "common boundary", geometries, geometries_count, &dim))
+ mixed_dim_err_msg(name, "common boundary", tools, tools_count, &dim);
+ if(geom) {
+ SCAD(geometry_ref_put(geom));
+ geom = NULL;
+ }
+ }
if(geom) {
- CHK(RES_OK == geometry_release(log, LOG_OUTPUT, geom));
+ SCAD(geometry_ref_put(geom));
geom = NULL;
}
if(tagout) gmshModelOccRemove(tagout, tagoutn, 1, &ierr);
@@ -1204,8 +1194,6 @@ scad_geometry_extrude
struct scad_geometry* extrude_geom = NULL;
struct scad_device* dev = get_device();
struct mem_allocator* allocator = NULL;
- int log;
- enum scad_log_refcounting option;
if(!geom || !dxdydz || !out_geometry) {
res = RES_BAD_ARG;
@@ -1214,8 +1202,6 @@ scad_geometry_extrude
ERR(check_device(FUNC_NAME));
allocator = dev->allocator;
- option = dev->options.Misc.LogOpenCascadeTagsRefCounting;
- log = option == Scad_log_all;
gmshModelOccExtrude(geom->gmsh_dimTags, geom->gmsh_dimTags_n, SPLIT3(dxdydz),
&tagout, &tagoutn, NULL, 0, NULL, 0, 0, &ierr);
@@ -1255,7 +1241,7 @@ exit:
return res;
error:
if(extrude_geom) {
- CHK(RES_OK == geometry_release(log, LOG_OUTPUT, extrude_geom));
+ SCAD(geometry_ref_put(extrude_geom));
extrude_geom = NULL;
}
goto exit;
@@ -1276,6 +1262,7 @@ scad_geometry_explode
int name_initialized = 0;
struct scad_device* dev = get_device();
struct mem_allocator* allocator = NULL;
+ const char* base_name = NULL;
if(!geom || !out_geometry || !out_geometry_n) {
res = RES_BAD_ARG;
@@ -1283,8 +1270,8 @@ scad_geometry_explode
}
ERR(check_device(FUNC_NAME));
- allocator = dev->allocator;
+ allocator = dev->allocator;
data = geom->gmsh_dimTags;
sz = geom->gmsh_dimTags_n;
@@ -1295,13 +1282,14 @@ scad_geometry_explode
goto error;
}
- if(prefix_name) {
+ base_name = prefix_name ? prefix_name : str_cget(&geom->name);
+ if(base_name) {
str_init(allocator, &name);
name_initialized = 1;
}
for(i=0; i<sz/2; ++i) {
- if(prefix_name) {
- ERR(str_set(&name, prefix_name));
+ if(base_name) {
+ ERR(str_set(&name, base_name));
ERR(str_append_printf(&name,"_%lu", (unsigned long)i));
ERR(scad_geometry_create(str_cget(&name), geom_array+i));
} else {
@@ -1328,7 +1316,7 @@ exit:
error:
if(geom_array) {
for(i = 0; i < sz/2; i++) {
- if(geom_array[i]) SCAD(geometry_delete(geom_array[i]));
+ if(geom_array[i]) SCAD(geometry_ref_put(geom_array[i]));
}
MEM_RM(allocator, geom_array);
geom_array = NULL;
@@ -1351,8 +1339,6 @@ scad_geometry_copy
struct scad_geometry* copy = NULL;
struct scad_device* dev = get_device();
struct mem_allocator* allocator = NULL;
- int log;
- enum scad_log_refcounting option;
if(!geom || !out_geometry) {
res = RES_BAD_ARG;
@@ -1361,8 +1347,6 @@ scad_geometry_copy
ERR(check_device(FUNC_NAME));
allocator = dev->allocator;
- option = dev->options.Misc.LogOpenCascadeTagsRefCounting;
- log = option == Scad_log_all;
sz1 = geom->gmsh_dimTags_n;
data1 = geom->gmsh_dimTags;
@@ -1387,7 +1371,7 @@ exit:
return res;
error:
if(copy) {
- CHK(RES_OK == geometry_release(log, LOG_OUTPUT, copy));
+ SCAD(geometry_ref_put(copy));
copy = NULL;
}
if(tagout) gmshModelOccRemove(tagout, tagoutn, 1, &ierr);
@@ -1468,8 +1452,6 @@ scad_geometries_partition
struct htable_tags_iterator it, end;
int ht_initialized = 0;
struct mem_allocator* allocator = NULL;
- int log;
- enum scad_log_refcounting option;
if(!geometries || !geometries_count || (allow_overlapping && !out_geometries)) {
res = RES_BAD_ARG;
@@ -1478,13 +1460,11 @@ scad_geometries_partition
ERR(check_device(FUNC_NAME));
allocator = dev->allocator;
- option = dev->options.Misc.LogOpenCascadeTagsRefCounting;
- log = option == Scad_log_all;
ERR(gather_tags(geometries, geometries_count, &data, &sz));
/* As a general principle, we don't remove gmsh objects directly; they are
- * only removed from scad_geometry_delete when their tags are no longuer used
+ * only removed from scad_geometry_ref_put when their tags are no longuer used
* by any star-cad geometry.
* Here we can safely use the remove flag in the non-overlapping case, as
* this ends in the same tags being reused for output. */
@@ -1619,7 +1599,9 @@ exit:
error:
if(geoms) {
for(i = 0; i < geometries_count; i++) {
- if(geoms[i]) CHK(RES_OK == geometry_release(log, LOG_OUTPUT, geoms[i]));
+ if(geoms[i]) {
+ SCAD(geometry_ref_put(geoms[i]));
+ }
}
}
if(tagout) {
@@ -1648,8 +1630,6 @@ scad_fragment_geometries
struct scad_geometry* geom = NULL;
struct scad_device* dev = get_device();
struct mem_allocator* allocator = NULL;
- int log;
- enum scad_log_refcounting option;
if(!geometries || !geometries_count || !tools || !tools_count || !out_geometry) {
res = RES_BAD_ARG;
@@ -1658,8 +1638,6 @@ scad_fragment_geometries
ERR(check_device(FUNC_NAME));
allocator = dev->allocator;
- option = dev->options.Misc.LogOpenCascadeTagsRefCounting;
- log = option == Scad_log_all;
ERR(gather_tags(geometries, geometries_count, &data1, &sz1));
ERR(gather_tags(tools, tools_count, &data2, &sz2));
@@ -1693,15 +1671,13 @@ exit:
return res;
error:
if(geom) {
- CHK(RES_OK == geometry_release(log, LOG_OUTPUT, geom));
+ SCAD(geometry_ref_put(geom));
geom = NULL;
}
if(tagout) gmshModelOccRemove(tagout, tagoutn, 1, &ierr);
goto exit;
}
-
-
res_T
scad_geometry_boundary
(const char* name,
@@ -1717,8 +1693,6 @@ scad_geometry_boundary
struct scad_geometry* geom = NULL;
struct scad_device* dev = get_device();
struct mem_allocator* allocator = NULL;
- int log;
- enum scad_log_refcounting option;
if(!geometries || !out_geometry) {
res = RES_BAD_ARG;
@@ -1727,8 +1701,6 @@ scad_geometry_boundary
ERR(check_device(FUNC_NAME));
allocator = dev->allocator;
- option = dev->options.Misc.LogOpenCascadeTagsRefCounting;
- log = option == Scad_log_all;
ERR(gather_tags(geometries, geometries_count, &data, &sz));
gmshModelGetBoundary(data, sz, &tagout, &tagoutn, 1, 0, 0, &ierr);
@@ -1752,7 +1724,7 @@ exit:
return res;
error:
if(geom) {
- CHK(RES_OK == geometry_release(log, LOG_OUTPUT, geom));
+ SCAD(geometry_ref_put(geom));
geom = NULL;
}
if(tagout) gmshModelOccRemove(tagout, tagoutn, 1, &ierr);
@@ -1831,7 +1803,7 @@ error:
ga_sz = 0;
if(geom_array) {
for(i=0; i<ga_sz; ++i) {
- if(geom_array[i]) SCAD(geometry_delete(geom_array[i]));
+ if(geom_array[i]) SCAD(geometry_ref_put(geom_array[i]));
}
MEM_RM(allocator, geom_array);
geom_array = NULL;
@@ -1857,6 +1829,9 @@ scad_geometry_normal
struct scad_geometry* out = NULL;
struct scad_device* dev = get_device();
struct mem_allocator* allocator = NULL;
+ double* coord = NULL;
+ double* pcoord = NULL;
+ double* normals = NULL;
if(!geom || !p || !N || !out_geometry) {
res = RES_BAD_ARG;
@@ -1879,11 +1854,8 @@ scad_geometry_normal
ERR(gather_tags(&surface, 1, &data, &sz));
for(i=0; sz/2; ++i) {
- double* coord = NULL;
- double* pcoord = NULL;
size_t pcoord_n;
size_t coord_n;
- double* normals = NULL;
size_t normals_n;
int dim = data[2*i];
int tag = data[2*i + 1];
@@ -1910,17 +1882,21 @@ scad_geometry_normal
ERR(device_register_tags(out));
d3_set(N, normals);
- gmshFree(coord);
- gmshFree(pcoord);
- gmshFree(normals);
break;
}
}
+ if(!out) { /* Could not find a matching surface */
+ res = RES_BAD_ARG;
+ goto error;
+ }
exit:
+ gmshFree(coord);
+ gmshFree(pcoord);
+ gmshFree(normals);
if(out_geometry) *out_geometry = out;
if(allocator) MEM_RM(allocator, data);
- if(surface) scad_geometry_delete(surface);
+ if(surface) SCAD(geometry_ref_put(surface));
return res;
error:
goto exit;
diff --git a/src/scad_geometry.h b/src/scad_geometry.h
@@ -21,17 +21,16 @@
#include <rsys/rsys.h>
#include <rsys/str.h>
#include <rsys/logger.h>
+#include <rsys/ref_count.h>
+
+struct mem_allocator;
struct scad_geometry {
int* gmsh_dimTags;
size_t gmsh_dimTags_n;
struct str name;
-};
-LOCAL_SYM res_T
-geometry_release
- (const int log,
- const enum log_type log_type,
- struct scad_geometry* geom);
+ ref_T ref;
+};
#endif
diff --git a/src/test_api.c b/src/test_api.c
@@ -22,6 +22,7 @@
#include <rsys/math.h>
#include <rsys/mem_allocator.h>
#include <rsys/logger.h>
+#include <rsys/dynamic_array_double.h>
#include <stdlib.h>
#include <stdio.h>
@@ -54,6 +55,7 @@ main(int argc, char* argv[])
struct scad_geometry* out_geoms[2];
struct mem_allocator allocator;
struct logger logger;
+ struct darray_double trg;
const char* name;
size_t i, c;
@@ -107,8 +109,11 @@ main(int argc, char* argv[])
geoms[1] = geom2;
OK(scad_add_sphere(NULL, p1, .1, &geom));
- BAD(scad_geometry_delete(NULL));
- OK(scad_geometry_delete(geom));
+ BAD(scad_geometry_ref_get(NULL));
+ OK(scad_geometry_ref_get(geom));
+ BAD(scad_geometry_ref_put(NULL));
+ OK(scad_geometry_ref_put(geom));
+ OK(scad_geometry_ref_put(geom));
BAD(scad_geometry_get_count(NULL, &c));
BAD(scad_geometry_get_count(geom1, NULL));
@@ -119,13 +124,13 @@ main(int argc, char* argv[])
BAD(scad_add_rectangle(NULL, p1, d1, NULL));
BAD(scad_add_rectangle("sphere 1", p1, d1, &geom)); /* Name already used */
OK(scad_add_rectangle(NULL, p1, d1, &geom));
- OK(scad_geometry_delete(geom));
+ OK(scad_geometry_ref_put(geom));
BAD(scad_add_disk(NULL, NULL, 1, &geom));
BAD(scad_add_disk(NULL, p1, 0, &geom));
BAD(scad_add_disk(NULL, p1, 1, NULL));
OK(scad_add_disk(NULL, p1, 1, &geom));
- OK(scad_geometry_delete(geom));
+ OK(scad_geometry_ref_put(geom));
BAD(scad_add_polygon(NULL, NULL, coord, 0, 3, &poly));
BAD(scad_add_polygon(NULL, get_position, coord, 0, 2, &poly));
@@ -137,7 +142,7 @@ main(int argc, char* argv[])
BAD(scad_add_box(NULL, p1, NULL, &geom));
BAD(scad_add_box(NULL, p1, d1, NULL));
OK(scad_add_box(NULL, p1, d1, &geom));
- OK(scad_geometry_delete(geom));
+ OK(scad_geometry_ref_put(geom));
BAD(scad_add_cylinder(NULL, NULL, d1, 2, 1, &geom));
BAD(scad_add_cylinder(NULL, p1, NULL, 2, 1, &geom));
@@ -146,13 +151,13 @@ main(int argc, char* argv[])
BAD(scad_add_cylinder(NULL, p1, d1, 2, 3*PI, &geom));
BAD(scad_add_cylinder(NULL, p1, d1, 2, 1, NULL));
OK(scad_add_cylinder(NULL, p1, d1, 2, 1, &geom));
- OK(scad_geometry_delete(geom));
+ OK(scad_geometry_ref_put(geom));
BAD(scad_add_sphere(NULL, NULL, 1, &geom));
BAD(scad_add_sphere(NULL, p1, 0, &geom));
BAD(scad_add_sphere(NULL, p1, 1, NULL));
OK(scad_add_sphere(NULL, p1, 1, &geom));
- OK(scad_geometry_delete(geom));
+ OK(scad_geometry_ref_put(geom));
/* BAD(scad_fuse_geometries(NULL, NULL, 0, geoms, 2, &geom)); */
BAD(scad_fuse_geometries(NULL, geoms, 2, NULL, 0, &geom));
@@ -160,7 +165,7 @@ main(int argc, char* argv[])
BAD(scad_fuse_geometries(NULL, &geom1, 1, NULL, 1, &geom));
BAD(scad_fuse_geometries(NULL, &geom1, 1, &geom2, 1, NULL));
OK(scad_fuse_geometries(NULL, &geom1, 1, &geom2, 1, &geom));
- OK(scad_geometry_delete(geom));
+ OK(scad_geometry_ref_put(geom));
/* BAD(scad_cut_geometries(NULL, NULL, 0, geoms, 2, &geom)); */
BAD(scad_cut_geometries(NULL, geoms, 2, NULL, 0, &geom));
@@ -168,7 +173,7 @@ main(int argc, char* argv[])
BAD(scad_cut_geometries(NULL, &geom1, 1, NULL, 1, &geom));
BAD(scad_cut_geometries(NULL, &geom1, 1, &geom2, 1, NULL));
OK(scad_cut_geometries(NULL, &geom1, 1, &geom2, 1, &geom));
- OK(scad_geometry_delete(geom));
+ OK(scad_geometry_ref_put(geom));
/* BAD(scad_intersect_geometries(NULL, NULL, 0, geoms, 2, &geom)); */
BAD(scad_intersect_geometries(NULL, geoms, 2, NULL, 0, &geom));
@@ -176,7 +181,7 @@ main(int argc, char* argv[])
BAD(scad_intersect_geometries(NULL, &geom1, 1, NULL, 1, &geom));
BAD(scad_intersect_geometries(NULL, &geom1, 1, &geom2, 1, NULL));
OK(scad_intersect_geometries(NULL, &geom1, 1, &geom2, 1, &geom));
- OK(scad_geometry_delete(geom));
+ OK(scad_geometry_ref_put(geom));
/* BAD(scad_geometries_common_boundaries(NULL, NULL, 0, geoms, 2, &geom)); */
BAD(scad_geometries_common_boundaries(NULL, geoms, 2, NULL, 0, &geom));
@@ -184,25 +189,25 @@ main(int argc, char* argv[])
BAD(scad_geometries_common_boundaries(NULL, &geom1, 1, NULL, 1, &geom));
BAD(scad_geometries_common_boundaries(NULL, &geom1, 1, &geom2, 1, NULL));
OK(scad_geometries_common_boundaries(NULL, &geom1, 1, &geom2, 1, &geom));
- OK(scad_geometry_delete(geom));
+ OK(scad_geometry_ref_put(geom));
BAD(scad_geometries_partition(NULL, 2, 1, out_geoms));
BAD(scad_geometries_partition(geoms, 0, 1, out_geoms));
BAD(scad_geometries_partition(geoms, 2, 1, NULL));
OK(scad_geometries_partition(geoms, 2, 1, out_geoms));
- OK(scad_geometry_delete(out_geoms[0]));
- OK(scad_geometry_delete(out_geoms[1]));
+ OK(scad_geometry_ref_put(out_geoms[0]));
+ OK(scad_geometry_ref_put(out_geoms[1]));
BAD(scad_geometry_boundary(NULL, NULL, 0, &geom));
BAD(scad_geometry_boundary(NULL, &geom1, 1, NULL));
OK(scad_geometry_boundary(NULL, &geom1, 1, &geom));
- OK(scad_geometry_delete(geom));
+ OK(scad_geometry_ref_put(geom));
BAD(scad_geometry_copy(NULL, NULL, &geom));
BAD(scad_geometry_copy(geom1, NULL, NULL));
BAD(scad_geometry_copy(geom1, "sphere 1", NULL)); /* Name already in use */
OK(scad_geometry_copy(geom1, "Sphere 1", &geom));
- OK(scad_geometry_delete(geom));
+ OK(scad_geometry_ref_put(geom));
BAD(scad_geometry_rename(NULL, NULL));
BAD(scad_geometry_rename(geom2, "sphere 1")); /* Name already in use */
@@ -221,8 +226,8 @@ main(int argc, char* argv[])
BAD(scad_geometry_extrude(poly, NULL, NULL, &geom));
BAD(scad_geometry_extrude(poly, NULL, d1, NULL));
OK(scad_geometry_extrude(poly, NULL, d1, &geom));
- OK(scad_geometry_delete(poly));
- OK(scad_geometry_delete(geom));
+ OK(scad_geometry_ref_put(poly));
+ OK(scad_geometry_ref_put(geom));
BAD(scad_scene_write(NULL));
ERR(scad_scene_write(""));
@@ -234,19 +239,36 @@ main(int argc, char* argv[])
ERR(scad_step_import("dont_exist.step", "step", &geom_array, &c));
OK(scad_step_import("/tmp/test.step", "step", &geom_array, &c));
for(i = 0; i < c; i++) {
- OK(scad_geometry_delete(geom_array[i]));
+ OK(scad_geometry_ref_put(geom_array[i]));
}
MEM_RM(&allocator, geom_array);
+ darray_double_init(&allocator, &trg);
+ BAD(scad_stl_get_data(NULL, 0, NULL));
+ BAD(scad_stl_get_data(geom2, 0, NULL));
+ OK(scad_stl_get_data(geom2, 0, &trg));
+ BAD(scad_stl_data_write(NULL, NULL, 0));
+ BAD(scad_stl_data_write(&trg, NULL, 0));
+ BAD(scad_stl_data_write(NULL, "/tmp/test", 0));
+ OK(scad_stl_data_write(&trg, "/tmp/test", 0));
+ OK(scad_stl_data_write(&trg, "/tmp/test", 1));
+ darray_double_release(&trg);
+
BAD(scad_stl_export(NULL, NULL, 0, 0));
BAD(scad_stl_export(geom2, NULL, 0, 0)); /* geom2 has no name */
OK(scad_stl_export(geom2, "/tmp/test", 0, 0));
+ OK(scad_stl_export(geom2, "/tmp/test", 0, 1));
OK(scad_stl_export(geom1, NULL, 0, 0));
-
- BAD(scad_stl_export_split(NULL, NULL, 0));
- BAD(scad_stl_export_split(geom2, NULL, 0)); /* geom2 has no name */
- OK(scad_stl_export_split(geom2, "/tmp/test", 0));
- OK(scad_stl_export_split(geom1, NULL, 0));
+ OK(scad_stl_export(geom1, NULL, 0, 1));
+
+ BAD(scad_stl_export_split(NULL, NULL, 0, 0));
+ BAD(scad_stl_export_split(geom2, NULL, 0, 0)); /* geom2 has no name */
+ OK(scad_stl_export_split(geom2, "/tmp/test", 0, 0));
+ BAD(scad_stl_export_split(geom2, "/tmp/test", 0, 0)); /* Produce same names */
+ OK(scad_stl_export_split(geom2, "/tmp/testb", 0, 1));
+ OK(scad_stl_export_split(geom1, NULL, 0, 0));
+ BAD(scad_stl_export_split(geom1, NULL, 0, 1)); /* Produce same names */
+ OK(scad_stl_export_split(geom1, "different_names", 0, 1));
BAD(scad_geometry_get_name(NULL, &name));
BAD(scad_geometry_get_name(geom1, NULL));