commit 4774911797f3283aed4421556280ba1b7eea9996
parent 1dfdcda8ebebb1900c6e63f88f7730705b7d5b0c
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Fri, 22 Aug 2025 10:51:35 +0200
Fix gmsh bugs on boolean operations
When used with the remove flag set to false (do not remove input
geometries), gmsh 4.14 introduces changes to the boolean operations
(cut, fuse, intersect) output. They no longer meet our needs.
We fix this by copying the input geometries and removing these copies
through the remove flag set to true.
The FIX_GMSH_BOOLEAN_OUTPUTS configuration symbol is introduced to help
run star-cad with[out] the fix to check future gmsh releases.
Diffstat:
2 files changed, 70 insertions(+), 1 deletion(-)
diff --git a/config.mk b/config.mk
@@ -8,6 +8,14 @@ BUILD_TYPE = RELEASE
#BUILD_TYPE = DEBUG
################################################################################
+# FIXME:
+# REMOVE THIS ONCE GMSH IS FIXED
+################################################################################
+
+CFLAGS_GMSH = \
+ -DFIX_GMSH_BOOLEAN_OUTPUTS
+
+################################################################################
# Tools
################################################################################
AR = ar
@@ -67,7 +75,8 @@ CFLAGS_COMMON =\
-fvisibility=hidden\
-fstrict-aliasing\
$(CFLAGS_HARDENED)\
- $(WFLAGS)
+ $(WFLAGS) \
+ $(CFLAGS_GMSH)
CFLAGS_DEBUG = -g $(CFLAGS_COMMON)
CFLAGS_RELEASE = -O2 -DNDEBUG $(CFLAGS_COMMON)
diff --git a/src/scad_geometry.c b/src/scad_geometry.c
@@ -1553,6 +1553,10 @@ scad_geometries_fuse
struct scad_geometry* geom = NULL;
struct scad_device* dev = get_device();
struct mem_allocator* allocator = NULL;
+#ifdef FIX_GMSH_BOOLEAN_OUTPUTS
+ int *tmp1 = NULL, *tmp2 = NULL;
+ size_t c1, c2;
+#endif
if(!geometries || !geometries_count || !tools || !tools_count || !out_geometry) {
res = RES_BAD_ARG;
@@ -1565,10 +1569,22 @@ scad_geometries_fuse
ERR(gather_tags(geometries, geometries_count, &data1, &sz1));
ERR(gather_tags(tools, tools_count, &data2, &sz2));
+#ifdef FIX_GMSH_BOOLEAN_OUTPUTS
+ gmshModelOccCopy(data1, sz1, &tmp1, &c1, &ierr);
+ ERR(gmsh_err_to_res_T(ierr));
+ gmshModelOccCopy(data2, sz2, &tmp2, &c2, &ierr);
+ ERR(gmsh_err_to_res_T(ierr));
+ /* We do remove gmsh objects here as they are temporary copies created to
+ * allow the remove flag to be used (gmsh is broken here if remove=0) */
+ gmshModelOccFuse(tmp1, c1, tmp2, c2, &tagout, &tagoutn, &map, &mapn, &mapnn,
+ -1, 1, 1, &ierr);
+#else
/* We don't remove gmsh objects here; they are only removed when their tags are
* no longer used by any star-cad geometry */
gmshModelOccFuse(data1, sz1, data2, sz2, &tagout, &tagoutn, &map, &mapn,
&mapnn, -1, 0, 0, &ierr);
+#endif
+
ASSERT(tagoutn % 2 == 0);
ERR(gmsh_err_to_res_T(ierr));
@@ -1584,6 +1600,10 @@ scad_geometries_fuse
ERR(device_register_tags(geom));
exit:
+#ifdef FIX_GMSH_BOOLEAN_OUTPUTS
+ gmshFree(tmp1);
+ gmshFree(tmp2);
+#endif
if(out_geometry) *out_geometry = geom;
if(allocator) {
MEM_RM(allocator, data1);
@@ -1658,6 +1678,10 @@ scad_geometries_cut
struct scad_geometry* geom = NULL;
struct scad_device* dev = get_device();
struct mem_allocator* allocator = NULL;
+#ifdef FIX_GMSH_BOOLEAN_OUTPUTS
+ int *tmp1 = NULL, *tmp2 = NULL;
+ size_t c1, c2;
+#endif
if(!geometries || !geometries_count || !tools || !tools_count || !out_geometry) {
res = RES_BAD_ARG;
@@ -1670,10 +1694,22 @@ scad_geometries_cut
ERR(gather_tags(geometries, geometries_count, &data1, &sz1));
ERR(gather_tags(tools, tools_count, &data2, &sz2));
+#ifdef FIX_GMSH_BOOLEAN_OUTPUTS
+ gmshModelOccCopy(data1, sz1, &tmp1, &c1, &ierr);
+ ERR(gmsh_err_to_res_T(ierr));
+ gmshModelOccCopy(data2, sz2, &tmp2, &c2, &ierr);
+ ERR(gmsh_err_to_res_T(ierr));
+ /* We do remove gmsh objects here as they are temporary copies created to
+ * allow the remove flag to be used (gmsh is broken here if remove=0) */
+ gmshModelOccCut(tmp1, c1, tmp2, c2, &tagout, &tagoutn, &map, &mapn,
+ &mapnn, -1, 1, 1, &ierr);
+#else
/* We don't remove gmsh objects here; they are only removed when their tags are
* no longer used by any star-cad geometry */
gmshModelOccCut(data1, sz1, data2, sz2, &tagout, &tagoutn, &map, &mapn,
&mapnn, -1, 0, 0, &ierr);
+#endif
+
ASSERT(tagoutn % 2 == 0);
ERR(gmsh_err_to_res_T(ierr));
@@ -1697,6 +1733,10 @@ exit:
gmshFree(mapn);
gmshFree(tagout);
free_gmsh_map(map, mapnn);
+#ifdef FIX_GMSH_BOOLEAN_OUTPUTS
+ gmshFree(tmp1);
+ gmshFree(tmp2);
+#endif
return res;
error:
if(ierr) {
@@ -1731,6 +1771,10 @@ scad_geometries_intersect
struct scad_geometry* geom = NULL;
struct scad_device* dev = get_device();
struct mem_allocator* allocator = NULL;
+#ifdef FIX_GMSH_BOOLEAN_OUTPUTS
+ int *tmp1 = NULL, *tmp2 = NULL;
+ size_t c1, c2;
+#endif
if(!geometries || !geometries_count || !tools || !tools_count || !out_geometry) {
res = RES_BAD_ARG;
@@ -1743,10 +1787,22 @@ scad_geometries_intersect
ERR(gather_tags(geometries, geometries_count, &data1, &sz1));
ERR(gather_tags(tools, tools_count, &data2, &sz2));
+#ifdef FIX_GMSH_BOOLEAN_OUTPUTS
+ gmshModelOccCopy(data1, sz1, &tmp1, &c1, &ierr);
+ ERR(gmsh_err_to_res_T(ierr));
+ gmshModelOccCopy(data2, sz2, &tmp2, &c2, &ierr);
+ ERR(gmsh_err_to_res_T(ierr));
+ /* We do remove gmsh objects here as they are temporary copies created to
+ * allow the remove flag to be used (gmsh is broken here if remove=0) */
+ gmshModelOccIntersect(tmp1, c1, tmp2, c2, &tagout, &tagoutn, &map,
+ &mapn, &mapnn, -1, 1, 1, &ierr);
+#else
/* We don't remove gmsh objects here; they are only removed when their tags are
* no longer used by any star-cad geometry */
gmshModelOccIntersect(data1, sz1, data2, sz2, &tagout, &tagoutn, &map, &mapn,
&mapnn, -1, 0, 0, &ierr);
+#endif
+
ASSERT(tagoutn % 2 == 0);
ERR(gmsh_err_to_res_T(ierr));
@@ -1772,6 +1828,10 @@ exit:
gmshFree(mapn);
gmshFree(tagout);
free_gmsh_map(map, mapnn);
+#ifdef FIX_GMSH_BOOLEAN_OUTPUTS
+ gmshFree(tmp1);
+ gmshFree(tmp2);
+#endif
return res;
error:
if(geom) {