star-cad

Geometric operators for computer-aided design
git clone git://git.meso-star.fr/star-cad.git
Log | Files | Refs | README | LICENSE

commit 6043d88d66add96e661afc757cced6d94f752d3b
Author: Benjamin Piaud <benjamin.piaud@meso-star.com>
Date:   Wed, 16 Mar 2022 15:58:01 +0100

First commit

Diffstat:
AMakefile | 41+++++++++++++++++++++++++++++++++++++++++
AREADME.md | 10++++++++++
Aconfig.mk | 10++++++++++
Asrc/scad.c | 469+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/scad.h | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/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; +}