commit 6043d88d66add96e661afc757cced6d94f752d3b
Author: Benjamin Piaud <benjamin.piaud@meso-star.com>
Date: Wed, 16 Mar 2022 15:58:01 +0100
First commit
Diffstat:
| A | Makefile | | | 41 | +++++++++++++++++++++++++++++++++++++++++ |
| A | README.md | | | 10 | ++++++++++ |
| A | config.mk | | | 10 | ++++++++++ |
| A | src/scad.c | | | 469 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/scad.h | | | 95 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/test.c | | | 37 | +++++++++++++++++++++++++++++++++++++ |
6 files changed, 662 insertions(+), 0 deletions(-)
diff --git a/Makefile b/Makefile
@@ -0,0 +1,41 @@
+.SUFFIXES: # Clean up default inference rules
+
+include config.mk
+
+SRC = src/scad.c
+
+OBJ = $(SRC:.c=.o)
+
+all: static_lib
+
+$(OBJ): config.mk
+
+static_lib: $(OBJ)
+ $(AR) $(AFLAGS) libscad.a $(OBJ)
+
+.SUFFIXES: .c .o
+.c.o:
+ $(CC) $(CFLAGS) -c $< -o $@
+
+#------------------------------------------------------------------------------
+
+test: $(OBJ) src/test.o
+ $(CC) -o $@ src/test.o $(OBJ) $(LDLIBS) $(LDFLAGS)
+
+src/test.o: src/test.c
+ $(CC) $(CFLAGS) -c $< -o $@
+
+clean:
+ @rm -f $(OBJ) libscad.a src/test.o test
+
+API = src/scad.h
+
+install: static_lib
+ mkdir -p $(PREFIX)/lib
+ mkdir -p $(PREFIX)/include/
+ cp libscad.a $(PREFIX)/lib
+ cp $(API) $(PREFIX)/include/
+
+uninstall:
+ rm -f $(PREFIX)/lib/libscad.a
+ rm -f $(PREFIX)/include/scad.h
diff --git a/README.md b/README.md
@@ -0,0 +1,10 @@
+# Star-Cad
+
+Star-Cad is a gmsh wrapper library.
+
+Star-Cad depends on :
+- gmsh https://gmsh.info/
+- Rsys https://gitlab.com/vaplv/rsys
+
+To build Star-Cad modify the config.mk to find Rsys and Gmsh on your system.
+Star-Cad is build as a static library.
diff --git a/config.mk b/config.mk
@@ -0,0 +1,10 @@
+CC = cc
+PREFIX = /usr/local
+INC = /usr/include
+LIB = /usr/lib
+
+AFLAGS = crs
+WFLAGS = -Wall -Wextra -Wmissing-declarations -Wmissing-prototypes -Wconversion -Wshadow
+CFLAGS = -O2 -std=c89 -pedantic -I$(INC) $(WFLAGS)
+LDFLAGS = -L$(LIB)
+LDLIBS = -lm -lrsys -lgmsh
diff --git a/src/scad.c b/src/scad.c
@@ -0,0 +1,469 @@
+#include "scad.h"
+
+res_T
+scad_init(void)
+{
+ res_T res = RES_OK;
+ int ierr = 0;
+ gmshInitialize(0, NULL, 1, 0, &ierr);
+ gmshModelAdd("model", &ierr);
+
+ gmshOptionSetNumber("Mesh.StlOneSolidPerSurface", 2, &ierr);
+ gmshOptionSetNumber("Mesh.MeshSizeFromPoints", 0, &ierr);
+ gmshOptionSetNumber("Mesh.MeshSizeFromCurvature", 1, &ierr);
+ gmshOptionSetNumber("Mesh.MinimumElementsPerTwoPi", 36, &ierr);
+ gmshOptionSetNumber("Mesh.MeshSizeExtendFromBoundary", 0, &ierr);
+
+ if (ierr !=0) goto error;
+
+exit:
+ return res;
+error:
+ FATAL("Can't initialize gmsh !\n");
+ goto exit;
+}
+
+res_T
+scad_release(void)
+{
+ int ierr = 0;
+ gmshFinalize(&ierr);
+
+ if (ierr != 0) goto error;
+
+exit:
+ return ierr;
+error:
+ FATAL("Can't release gmsh !\n");
+ goto exit;
+}
+
+res_T
+scad_synchronize(void)
+{
+ int ierr;
+ gmshModelOccSynchronize(&ierr);
+ return ierr;
+}
+
+res_T
+scad_run_ui(void)
+{
+ int ierr;
+ gmshFltkRun(&ierr);
+ return ierr;
+}
+
+
+res_T
+scad_concat(scad_geom_T* geom1, const scad_geom_T geom2)
+{
+ int res = RES_OK;
+ int i;
+
+ if (!geom2) {FATAL("Can't concat \n"); res = RES_BAD_ARG; goto error;}
+
+ for (i=0; i<(int)sa_size(geom2) ; ++i)
+ {
+ sa_push(*geom1, geom2[i]);
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+
+res_T
+scad_addbox
+(const double xyz[3], const double dxdydz[3], scad_geom_T* geom)
+{
+ res_T res = RES_OK;
+ int ierr = 0;
+ int tag = 0;
+
+ if(!xyz || !dxdydz) {
+ FATAL("Invalid data !\n");
+ return RES_BAD_ARG;
+ }
+
+ tag = gmshModelOccAddBox(xyz[0], xyz[1], xyz[2],
+ dxdydz[0], dxdydz[1], dxdydz[2],
+ -1,
+ &ierr);
+
+ if (ierr !=0) goto error;
+
+ if (*geom != NULL) *geom = NULL;
+ sa_push(*geom,3);
+ sa_push(*geom,tag);
+
+exit:
+ return res;
+error:
+ res = ierr;
+ FATAL("Can't create box !\n");
+ goto exit;
+
+}
+
+
+res_T
+scad_addcylinder
+(const double xyz[3], const double axis[3], const double rad, const double angle, scad_geom_T* geom)
+{
+ res_T res = RES_OK;
+ int ierr = 0;
+ int tag = 0;
+
+ if(!xyz || !axis) {
+ FATAL("Invalid data !\n");
+ return RES_BAD_ARG;
+ }
+
+ tag = gmshModelOccAddCylinder(xyz[0],
+ xyz[1],
+ xyz[2],
+ axis[0],
+ axis[1],
+ axis[2],
+ rad,
+ -1,
+ angle,
+ &ierr);
+
+ if (ierr !=0) goto error;
+
+ if (*geom != NULL) *geom = NULL;
+ sa_push(*geom,3);
+ sa_push(*geom,tag);
+
+exit:
+ return res;
+error:
+ res = ierr;
+ FATAL("Can't create cylinder !\n");
+ goto exit;
+}
+
+int
+scad_addsphere
+(const double xyz[3], const double rad, scad_geom_T* geom)
+{
+ res_T res = RES_OK;
+ int ierr = 0;
+ int tag = 0;
+
+ if(!xyz) {
+ FATAL("Invalid data !\n");
+ return RES_BAD_ARG;
+ }
+
+ tag = gmshModelOccAddSphere(xyz[0],
+ xyz[1],
+ xyz[2],
+ rad,
+ -1,
+ -PI/2,
+ PI/2,
+ 2*PI,
+ &ierr);
+
+ if (ierr !=0) goto error;
+
+ if (*geom != NULL) *geom = NULL;
+ sa_push(*geom,3);
+ sa_push(*geom,tag);
+
+exit:
+ return res;
+error:
+ res = ierr;
+ FATAL("Can't create sphere !\n");
+ goto exit;
+}
+
+res_T
+scad_remove(scad_geom_T geom)
+{
+ res_T res = RES_OK;
+ int ierr = 0;
+
+ gmshModelOccRemove(geom, sa_size(geom), 0, &ierr);
+
+ if (ierr !=0) goto error;
+
+exit:
+ return res;
+error:
+ res = ierr;
+ FATAL("Can't remove geometry !\n");
+ goto exit;
+}
+
+
+res_T
+scad_fuse
+(const scad_geom_T geom1, const scad_geom_T geom2, scad_geom_T* out, const int remove)
+{
+ res_T res = RES_OK;
+ int ierr, i;
+ int* tagout;
+ int** map = NULL;
+ size_t tagoutn, *mapn, mapnn;
+
+ gmshModelOccFuse(geom1, sa_size(geom1),
+ geom2, sa_size(geom2),
+ &tagout, &tagoutn,
+ &map, &mapn, &mapnn,
+ -1,
+ remove,
+ remove,
+ &ierr);
+
+ if (ierr != 0 ) {FATAL("Fuse not possible !\n"); goto error;}
+
+ for (i=0; i<(int)tagoutn; ++i){
+ sa_push(*out, tagout[i]);
+ }
+
+exit:
+ if (tagout) free(tagout);
+ if (mapn) free(mapn);
+ if (map) free(map);
+ return res;
+error:
+ goto exit;
+}
+
+
+res_T
+scad_cut
+(const scad_geom_T geom1, const scad_geom_T geom2, scad_geom_T* out, const int remove)
+{
+ res_T res = RES_OK;
+ int ierr, i;
+ int* tagout;
+ int** map = NULL;
+ size_t tagoutn, *mapn, mapnn;
+
+ gmshModelOccCut(geom1, sa_size(geom1),
+ geom2, sa_size(geom2),
+ &tagout, &tagoutn,
+ &map, &mapn, &mapnn,
+ -1,
+ remove,
+ remove,
+ &ierr);
+
+ if (ierr != 0 ) {FATAL("Cut not possible !\n"); goto error;}
+
+ for (i=0; i<(int)tagoutn; ++i){
+ sa_push(*out, tagout[i]);
+ }
+
+exit:
+ if (tagout) free(tagout);
+ if (mapn) free(mapn);
+ if (map) free(map);
+ return res;
+error:
+ goto exit;
+}
+
+res_T
+scad_intersect
+(const scad_geom_T geom1, const scad_geom_T geom2, scad_geom_T* out, const int remove)
+{
+ res_T res = RES_OK;
+ int ierr, i;
+ int* tagout;
+ int** map = NULL;
+ size_t tagoutn, *mapn, mapnn;
+
+ gmshModelOccIntersect(geom1, sa_size(geom1),
+ geom2, sa_size(geom2),
+ &tagout, &tagoutn,
+ &map, &mapn, &mapnn,
+ -1,
+ remove,
+ remove,
+ &ierr);
+
+ if (ierr != 0 ) {FATAL("Intersection not possible !\n"); goto error;}
+
+ for (i=0; i<(int)tagoutn; ++i){
+ sa_push(*out, tagout[i]);
+ }
+
+exit:
+ if (tagout) free(tagout);
+ if (mapn) free(mapn);
+ if (map) free(map);
+ return res;
+error:
+ goto exit;
+}
+
+
+res_T
+scad_fragment
+(const scad_geom_T geom1, const scad_geom_T geom2, scad_geom_T* out, const int remove)
+{
+ res_T res = RES_OK;
+ int ierr, i;
+ int* tagout;
+ int** map = NULL;
+ size_t tagoutn, *mapn, mapnn;
+
+ gmshModelOccFragment(geom1, sa_size(geom1),
+ geom2, sa_size(geom2),
+ &tagout, &tagoutn,
+ &map, &mapn, &mapnn,
+ -1,
+ remove,
+ remove,
+ &ierr);
+
+ if (ierr != 0 ) {FATAL("Fragment not possible !\n"); goto error;}
+
+ for (i=0; i<(int)tagoutn; ++i){
+ sa_push(*out, tagout[i]);
+ }
+
+exit:
+ if (tagout) free(tagout);
+ if (mapn) free(mapn);
+ if (map) free(map);
+ return res;
+error:
+ goto exit;
+}
+
+
+res_T
+scad_translate
+(scad_geom_T geom, const double dxdydz[3])
+{
+ res_T res = RES_OK;
+ int ierr;
+
+ if (!geom || !dxdydz){
+ FATAL("Invalid data !\n");
+ return RES_BAD_ARG;
+ }
+
+ gmshModelOccTranslate(geom, sa_size(geom),
+ dxdydz[0],
+ dxdydz[1],
+ dxdydz[2],
+ &ierr);
+
+ if (ierr != 0 ) {FATAL("Translation not possible !\n"); goto error;}
+
+exit:
+ return res;
+error:
+ res = ierr;
+ goto exit;
+}
+
+res_T
+scad_rotate
+(scad_geom_T geom, const double pt[3], const double axis[3], const double angle)
+{
+ res_T res = RES_OK;
+ int ierr;
+
+ if (!geom || !pt || !axis){
+ FATAL("Invalid data !\n");
+ return RES_BAD_ARG;
+ }
+
+ gmshModelOccRotate(geom, sa_size(geom),
+ pt[0],
+ pt[1],
+ pt[2],
+ axis[0],
+ axis[1],
+ axis[2],
+ angle,
+ &ierr);
+
+ if (ierr != 0 ) {FATAL("Rotation not possible !\n"); goto error;}
+
+exit:
+ return res;
+error:
+ res = ierr;
+ goto exit;
+}
+
+res_T
+scad_conformal_mesh(void)
+{
+ int ierr = 0;
+ int* dimTags;
+ size_t dimTags_n;
+
+ gmshModelOccSynchronize(&ierr);
+ gmshModelOccGetEntities(&dimTags, &dimTags_n, 3, &ierr);
+ if ( ierr == 0 && dimTags_n > 2) gmshModelOccRemoveAllDuplicates(&ierr);
+ gmshModelOccSynchronize(&ierr);
+ gmshModelMeshGenerate(2, &ierr);
+
+ return ierr;
+}
+
+
+res_T
+scad_stl_export(const scad_geom_T geom, char *prefix)
+{
+ res_T res = RES_OK;
+ int ierr;
+ int i;
+ int* tagout;
+ int* tags = NULL;
+ size_t tagoutn;
+ int group, dimtag[2];
+
+ for (i=0; i<(int)sa_size(geom)/2; ++i)
+ {
+ gmshModelMeshSetOutwardOrientation(geom[2*i+1], &ierr);
+ }
+
+ gmshModelGetBoundary(geom, sa_size(geom),
+ &tagout, &tagoutn,
+ 1,
+ 0,
+ 0,
+ &ierr);
+
+ if (ierr !=0) goto error;
+
+
+ for(i=0; i<(int)tagoutn/2; ++i){
+ sa_push(tags, tagout[2*i + 1]);
+ }
+
+ group = gmshModelAddPhysicalGroup(2, tags, tagoutn/2,
+ -1,
+ &ierr);
+ if (ierr !=0) goto error;
+
+ gmshWrite(prefix, &ierr);
+ if (ierr !=0) goto error;
+
+ dimtag[0]=2;
+ dimtag[1]=group;
+ gmshModelRemovePhysicalGroups(dimtag, 2, &ierr);
+ if (ierr !=0) goto error;
+
+exit:
+ if (tagout) free(tagout);
+ if (tags) sa_release(tags);
+ return res;
+error:
+ goto exit;
+}
diff --git a/src/scad.h b/src/scad.h
@@ -0,0 +1,95 @@
+#ifndef SCAD_H
+#define SCAD_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <gmshc.h>
+#include <rsys/rsys.h>
+#include <rsys/stretchy_array.h>
+#include <rsys/math.h>
+#include <string.h>
+
+/* wrapping of dimTags gmsh description */
+typedef int* scad_geom_T;
+#define SCAD_GEOM_NULL_ NULL
+static const scad_geom_T SCAD_GEOM_NULL = SCAD_GEOM_NULL_;
+
+/* remove the handler but not the geomtry */
+/* to remove geometry, use scad_geom_remove */
+static FINLINE
+res_T scad_geom_release(scad_geom_T geom)
+{
+ sa_release(geom);
+ return RES_OK;
+}
+
+/*****************************************************************************/
+/*****************************************************************************/
+/*****************************************************************************/
+res_T
+scad_init(void);
+
+res_T
+scad_release(void);
+
+res_T
+scad_synchronize(void);
+
+res_T
+scad_run_ui(void);
+
+res_T
+scad_addbox
+(const double xyz[3], const double dxdydz[3], scad_geom_T* geom);
+
+res_T
+scad_addcylinder
+(const double xyz[3], const double axis[3], const double rad, const double angle, scad_geom_T* geom);
+
+res_T
+scad_addsphere
+(const double xyz[3], const double rad, scad_geom_T* geom);
+
+res_T
+scad_remove(scad_geom_T geom);
+
+res_T
+scad_concat(scad_geom_T* geom1, const scad_geom_T geom2);
+
+#define DELETE 1
+#define NODELETE 0
+res_T
+scad_fuse
+(const scad_geom_T geom1, const scad_geom_T geom2, scad_geom_T* out, const int remove);
+
+res_T
+scad_cut
+(const scad_geom_T geom1, const scad_geom_T geom2, scad_geom_T* out, const int remove);
+
+res_T
+scad_intersect
+(const scad_geom_T geom1, const scad_geom_T geom2, scad_geom_T* out, const int remove);
+
+res_T
+scad_fragment
+(const scad_geom_T geom1, const scad_geom_T geom2, scad_geom_T* out, const int remove);
+
+res_T
+scad_translate
+(scad_geom_T geom, const double dxdydz[3]);
+
+res_T
+scad_rotate
+(scad_geom_T geom, const double pt[3], const double axis[3], const double angle);
+
+res_T
+scad_conformal_mesh(void);
+
+res_T
+scad_stl_export(const scad_geom_T geom, char *prefix);
+
+/*****************************************************************************/
+/*****************************************************************************/
+/*****************************************************************************/
+
+#endif /* SCAD_H */
diff --git a/src/test.c b/src/test.c
@@ -0,0 +1,37 @@
+#include "scad.h"
+
+#define ERR(Expr) if((res = (Expr)) != RES_OK) goto error; else (void)0
+
+int
+main(int argc, char* argv[])
+{
+ res_T res = RES_OK;
+ double p1[3] = {0, 0, 0};
+ double p2[3] = {0.25, 0.25, 0.8};
+ double d1[3] = {1, 1, 1};
+ double d2[3] = {0.5, 0.5, 0.5};
+ scad_geom_T box1 = SCAD_GEOM_NULL;
+ scad_geom_T box2 = SCAD_GEOM_NULL;
+ scad_geom_T cut = SCAD_GEOM_NULL;
+
+ (void)argc; (void)argv;
+
+ ERR(scad_init());
+ ERR(scad_addbox(p1, d1, &box1));
+ ERR(scad_addbox(p2, d2, &box2));
+ ERR(scad_intersect(box1, box2, &cut, NODELETE));
+
+ ERR(scad_synchronize());
+ ERR(scad_run_ui());
+ /*ERR(scad_conformal_mesh());*/
+ /*ERR(scad_stl_export(cut, "mesh.stl"));*/
+
+exit:
+ scad_geom_release(box1);
+ scad_geom_release(box2);
+ scad_geom_release(cut);
+ scad_release();
+ return res;
+error:
+ goto exit;
+}