├── .gitignore ├── CMakeLists.txt ├── LICENSE.md ├── README.md ├── TODO.md ├── doc └── images │ ├── TMeshExample.png │ ├── bdrySizeFun.png │ ├── exampleMesh.png │ ├── performance.png │ ├── qtree.png │ ├── qtree_gray.png │ └── tMesh.png ├── share ├── cmake │ ├── compiler_flags.cmake │ └── directories.cmake ├── files │ ├── comment_test.para │ ├── example.para │ ├── simple.para │ ├── size_function.para │ └── square.para └── python │ ├── performance.py │ ├── plot_boundary.py │ ├── plot_mesh.py │ ├── plot_qtree.py │ └── spiral.py └── src └── tmesh ├── CMakeLists.txt ├── include └── tmesh │ ├── bstrlib.h │ ├── dbg.h │ ├── minunit.h │ ├── tinyexpr.h │ ├── tmBdry.h │ ├── tmEdge.h │ ├── tmFront.h │ ├── tmList.h │ ├── tmMesh.h │ ├── tmNode.h │ ├── tmParam.h │ ├── tmQtree.h │ ├── tmTri.h │ └── tmTypedefs.h ├── src ├── bstrlib.c ├── main.c ├── tinyexpr.c ├── tmBdry.c ├── tmEdge.c ├── tmFront.c ├── tmList.c ├── tmMesh.c ├── tmNode.c ├── tmParam.c ├── tmQtree.c └── tmTri.c └── test ├── geom_tests.c ├── geom_tests.h ├── tmList_tests.c ├── tmList_tests.h ├── tmParam_tests.c ├── tmParam_tests.h ├── tmesh_cylinder.c ├── tmesh_cylinder.h ├── tmesh_examples.c ├── tmesh_examples.h ├── tmesh_tests.c ├── tmesh_tests.h └── unit_tests.c /.gitignore: -------------------------------------------------------------------------------- 1 | build/* 2 | bin/* 3 | lib/* 4 | *.o 5 | *.dat 6 | share/python/pics/*.png 7 | src/tags 8 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ############################################################## 2 | # LEARN C THE HARD WAY # 3 | ############################################################## 4 | # prerequisites 5 | cmake_minimum_required( VERSION 3.5.2 ) 6 | project( Triangular-Mesh-Generator ) 7 | 8 | # enable testing support 9 | enable_testing() 10 | 11 | # Include cmake files 12 | include( "${CMAKE_SOURCE_DIR}/share/cmake/directories.cmake" ) 13 | include( "${CMAKE_SOURCE_DIR}/share/cmake/compiler_flags.cmake" ) 14 | 15 | #------------------------------------------------------------- 16 | # Define modules 17 | #------------------------------------------------------------- 18 | add_subdirectory( ${SRC}/tmesh ) 19 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Florian Setzwein 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TMesh 2 | ----------------------------- 3 | tMesh-Grid 4 | 5 | 6 | **TMesh** is a small program to create two-dimensional triangular grids, which can 7 | be used for Finite Element Methods or Computational Fluid Dynamics applications. 8 | The triangles are generated with an advancing-front method, for which the user must only provide edge segments that define the boundaries of the domain. Furthermore it is possible to refine 9 | triangles locally with a user-defined size function. 10 | 11 | ## Installation 12 | **TMesh** is just base on the static library **libtmesh.a**, generated in the *lib*-directory of this repository. 13 | It is automatically created upon compilation with cmake. 14 | For installation, just create a build directory and run 15 | ```sh 16 | cmake .. 17 | make install 18 | ``` 19 | 20 | ## Usage of TMesh 21 | **TMesh** takes a parameter-file as input for the mesh generation. Sample files are given in *share/files/*. 22 | Basically, one only needs to define a few global parameters and the mesh boundaries in terms 23 | of boundary nodes and edges. 24 | There is the possibility to assign markers to the boundaries and to each boundary-edge. 25 | The only purpose of these markers is to identify these boundaries/edges later when the meshing is generated. 26 | Here is a simple example to create a mesh using **TMesh**: 27 | It is even possible to provide simple size function expressions through the input file. 28 | ```sh 29 | #----------------------------------------------------------- 30 | # TMESH 31 | #----------------------------------------------------------- 32 | Global element size: 0.5 33 | Number of quadtree elements: 50 34 | Mesh bounding box: -10.0, -10.0, 20.0, 20.0 35 | Size function: 0.5-0.43*exp(-0.03*((1.-x)*(2.-x)+(9.-y)*(9.-y))) 36 | 37 | 38 | #----------------------------------------------------------- 39 | # NODES 40 | #----------------------------------------------------------- 41 | Define nodes: 42 | 1.0, 1.0 43 | 10.0, 0.0 44 | 10.0, 10.0 45 | 0.0, 10.0 46 | 2.0, 2.0 47 | 2.0, 4.0 48 | 4.0, 4.0 49 | 4.0, 2.0 50 | 6.0, 5.0 51 | 7.0, 7.0 52 | 9.0, 4.0 53 | End nodes 54 | 55 | #----------------------------------------------------------- 56 | # BOUNDARIES 57 | #----------------------------------------------------------- 58 | # For every boundary an integer is assigned as marker. 59 | # Boundary edges are defined by: 60 | # 61 | # iStart, iEnd, edgeMarker, edgeRefinement 62 | # 63 | # > iStart and iEnd corresponds to the indices of the 64 | # nodes define above 65 | # > edgeMarker is an integer that is assigned to the 66 | # respective edge 67 | # > edgeRefinement is a double used to control the local 68 | # refinement near share edges (>0) 69 | # 70 | # > Exterior boundaries must be defined counter-clockwise 71 | # > Interior boundaries must be defined clockwise 72 | # 73 | #----------------------------------------------------------- 74 | Define exterior boundary: 1 75 | 0, 1, 0, 1.4 76 | 1, 2, 0, 1.4 77 | 2, 3, 0, 1.4 78 | 3, 0, 0, 1.4 79 | End exterior boundary 80 | 81 | Define interior boundary: 1 82 | 4, 5, 1, 1.6 83 | 5, 6, 1, 1.6 84 | 6, 7, 1, 1.6 85 | 7, 4, 1, 1.6 86 | End interior boundary 87 | 88 | Define interior boundary: 2 89 | 8, 9, 2, 1.5 90 | 9, 10, 2, 1.5 91 | 10, 8, 2, 1.5 92 | End interior boundary 93 | ``` 94 | 95 | The mesh is created with 96 | ```sh 97 | ./bin/TMesh example.para 98 | ``` 99 | Here is the generated mesh: 100 | Example-Grid 101 | 102 | ## Create a plot of your mesh 103 | The python script `share/python/plot_mesh.py` can create simple mesh plots from TMesh's output. 104 | Simply write TMesh's output to a text file 105 | 106 | ```sh 107 | ./bin/TMesh example.para > your_mesh.txt 108 | ``` 109 | 110 | and then run the Python script with 111 | 112 | ```sh 113 | python share/python/plot_mesh.py your_mesh.txt your_meshplot.png 114 | ``` 115 | 116 | ## Usage of C-Functions 117 | A detailed description on how to define a mesh is given in the examples under 118 | *src/tmesh/test*. 119 | 120 | Every mesh is defined by an exterior boundary and several more interior boundaries. 121 | These boundaries consist of edge segments, which connect two nodes. 122 | Besides this, it is also necessary to provide a size-function `size_fun` to the mesh, which 123 | defines the local element size in the domain. 124 | First, create a new mesh object: 125 | ```sh 126 | tmMesh *mesh = tmMesh_create(xy_min, xy_max, N, size_fun); 127 | ``` 128 | Here, `xy_min` and `xy_max` define the bounding box of the entire domain, `N` is the number of elements that are stored in the underlying quadtree structure until a quad is refined. 129 | Next, define some vertices for the exterior boundary: 130 | ```sh 131 | tmNode *n0 = tmNode_create(mesh, xy0); 132 | tmNode *n1 = tmNode_create(mesh, xy1); 133 | tmNode *n2 = tmNode_create(mesh, xy2); 134 | ``` 135 | `xy0`, `xy1`, `xy2` define the node coordinates, e.g. `tmDouble xy0[2] = { -1.0, -1.0 };`. 136 | Now create the exterior boundary and add the edge segments to it. 137 | **IMPORTANT**: Exteriror boundary edge segments must be defined in a **counter-clockwise** manner, such that all edge normals point to the inside of the domain. 138 | ```sh 139 | tmBdry *bdry_ext = tmMesh_addBdry(mesh, FALSE, 0); 140 | tmEdge *e0 = tmBdry_edgeCreate(bdry_ext, n0, n1, 0, 1.0); 141 | tmEdge *e1 = tmBdry_edgeCreate(bdry_ext, n1, n2, 0, 1.0); 142 | tmEdge *e2 = tmBdry_edgeCreate(bdry_ext, n2, n0, 0, 1.0); 143 | ``` 144 | Interior boundaries are defined in a similar manner, but the segments must be defined in **clockwise** direction. 145 | ```sh 146 | tmNode *n3 = tmNode_create(mesh, xy3); 147 | tmNode *n4 = tmNode_create(mesh, xy4); 148 | tmNode *n5 = tmNode_create(mesh, xy5); 149 | 150 | tmBdry *bdry_int = tmMesh_addBdry(mesh, TRUE, 1); 151 | tmEdge *e3 = tmBdry_edgeCreate(bdry_int, n3, n4, 1, 1.0); 152 | tmEdge *e4 = tmBdry_edgeCreate(bdry_int, n4, n5, 1, 1.0); 153 | tmEdge *e5 = tmBdry_edgeCreate(bdry_int, n5, n3, 1, 1.0); 154 | ``` 155 | Finally, the advancing-front meshing is performed using 156 | ```sh 157 | tmMesh_ADFMeshing(mesh); 158 | ``` 159 | The final mesh can be printed to the command line with 160 | ```sh 161 | tmMesh_printMesh(mesh); 162 | ``` 163 | and the output of this function can be rendered with a small Python script **plot_mesh.py**, 164 | which is located in the directory *share/python*. 165 | 166 | Example-Grid 167 | 168 | ### Custom Element Sizing 169 | The local element size can either be defined through a size function defined by the user or 170 | by the boundary edges. Elements near sharp angles are automatically refined. 171 | 172 | SizeFunction 173 | 174 | ## Benchmarks 175 | tMesh-Grid 176 | 177 | **TMesh** uses an adaptive quadtree structure to store vertices, edges and triangles in an accessible way. This allows to find any existing object in the meshing process with an average complexity of N log. 178 | The quadtree is refined and coarsened automatically as objects are inserted or removed from the structure. 179 | 180 | For profiling of a test-binary: 181 | * Compile with `-pg` (default in debugging mode) 182 | * Run the test binary 183 | * Profile with: `gprof test gmon.out > prof_output` 184 | 185 | ### Qtree search benchmark 186 | Here's a short benchmark of the underlying quadtree structure. Its the output from the test-function `test_tmQtree_performance()` for various numbers of vertices. 187 | | Nodes | Qtree | Brute Force | 188 | | :----------: | :----------: | :----------: | 189 | | 10000 | 0.0 s | 0.6 s | 190 | | 20000 | 0.1 s | 2.6 s | 191 | | 30000 | 0.3 s | 8.2 s | 192 | | 50000 | 0.8 s | 38.4 s | 193 | | 100000 | 3.5 s | 371.7 s | 194 | 195 | 196 | ### Triangular mesh generation benchmark 197 | This plot shows the performance of **TMesh** for the generation of to simple meshes, 198 | defined in the test function `test_tmFront_simpleMesh2()` and `test_tmBdry_sizeFun()`. 199 | 200 | tMesh-Grid 201 | 202 | ## Todos 203 | * Python-Interface 204 | * Delaunay-refinement for generated grids 205 | * Better output format of generated meshes, e.g. HDF5 or netCDF. 206 | 207 | ## Used Libraries 208 | * [The Better String Library](http://bstring.sourceforge.net) 209 | * [TinyExpr](https://github.com/codeplea/tinyexpr) 210 | * Some snippets from Zed Shaw's [Learn C the hard way](https://github.com/zedshaw/learn-c-the-hard-way-lectures) 211 | 212 | ## Sources 213 | * o'Rourke, Joseph. Computational geometry in C. Cambridge university press, 1998. 214 | * [Shewchuk, Jonathan R. Lecture Notes on Delaunay Mesh Generation, February 5, 2012](https://people.eecs.berkeley.edu/~jrs/meshpapers/delnotes.pdf) 215 | * [Jonathan R. Shewchuk's free course material on Mesh Generation and Geometry Processing in Graphics, Engineering, and Modeling ](https://people.eecs.berkeley.edu/~jrs/mesh/) 216 | * Lo, Daniel SH. Finite element mesh generation. CRC Press, 2014 217 | * Blazek, Jiri. Computational fluid dynamics: principles and applications. Butterworth-Heinemann, 2015 218 | * Zed A. Shaw, Learn C the Hard Way (this is where the testing structure and the list functions are coming from) 219 | 220 | ## License 221 | The project is licensed under the MIT License - see the LICENSE file for details. 222 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # ToDo List 2 | * Remove bug: Qtree stucks in loop, as several points lying directly on top of each other are created 3 | -------------------------------------------------------------------------------- /doc/images/TMeshExample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FloSewn/tmesh/28a3d7c5e6f3b7c8763dcd7433122e3a0a530e3d/doc/images/TMeshExample.png -------------------------------------------------------------------------------- /doc/images/bdrySizeFun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FloSewn/tmesh/28a3d7c5e6f3b7c8763dcd7433122e3a0a530e3d/doc/images/bdrySizeFun.png -------------------------------------------------------------------------------- /doc/images/exampleMesh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FloSewn/tmesh/28a3d7c5e6f3b7c8763dcd7433122e3a0a530e3d/doc/images/exampleMesh.png -------------------------------------------------------------------------------- /doc/images/performance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FloSewn/tmesh/28a3d7c5e6f3b7c8763dcd7433122e3a0a530e3d/doc/images/performance.png -------------------------------------------------------------------------------- /doc/images/qtree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FloSewn/tmesh/28a3d7c5e6f3b7c8763dcd7433122e3a0a530e3d/doc/images/qtree.png -------------------------------------------------------------------------------- /doc/images/qtree_gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FloSewn/tmesh/28a3d7c5e6f3b7c8763dcd7433122e3a0a530e3d/doc/images/qtree_gray.png -------------------------------------------------------------------------------- /doc/images/tMesh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FloSewn/tmesh/28a3d7c5e6f3b7c8763dcd7433122e3a0a530e3d/doc/images/tMesh.png -------------------------------------------------------------------------------- /share/cmake/compiler_flags.cmake: -------------------------------------------------------------------------------- 1 | 2 | ################################################################################ 3 | # Define Build Type # 4 | ################################################################################ 5 | 6 | # default build type 7 | if( NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES ) 8 | 9 | # set the default build type 10 | message( STATUS "Setting build type to 'Debug' as none was specified." ) 11 | set( CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE ) 12 | 13 | # set the possible values of build type 14 | set_property( CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" ) 15 | 16 | endif() 17 | 18 | 19 | ################################################################################ 20 | # Compiler FLags # 21 | ################################################################################ 22 | 23 | # set compiler definition 24 | if( CMAKE_C_COMPILER_ID STREQUAL "GNU" ) 25 | string( APPEND MY_CMAKE_C_FLAGS "-DGNU" ) 26 | elseif( CMAKE_C_COMPILER_ID STREQUAL "Intel" ) 27 | string( APPEND MY_CMAKE_C_FLAGS "-DINTEL" ) 28 | endif() 29 | 30 | # define coding standards 31 | if( CMAKE_C_COMPILER_ID STREQUAL "GNU" ) 32 | string( APPEND MY_CMAKE_C_FLAGS " -std=c99" ) 33 | elseif( CMAKE_C_COMPILER_ID STREQUAL "Intel" ) 34 | string( APPEND MY_CMAKE_C_FLAGS " -std=c99" ) 35 | endif() 36 | 37 | 38 | ################################# 39 | # Compiler Flags (Debug Mode) # 40 | ################################# 41 | 42 | # set debug compiler flags 43 | if( CMAKE_BUILD_TYPE STREQUAL "Debug" ) 44 | 45 | # produce debugging information 46 | string( APPEND MY_CMAKE_C_FLAGS " -g" ) 47 | 48 | # disable optimization 49 | string( APPEND MY_CMAKE_C_FLAGS " -O0" ) 50 | 51 | # disable optimization 52 | string( APPEND MY_CMAKE_C_FLAGS " -pg" ) 53 | 54 | if( CMAKE_C_COMPILER_ID STREQUAL "GNU" ) 55 | 56 | # detect unused variables 57 | #string( APPEND MY_CMAKE_C_FLAGS " -Wunused-variable" ) 58 | 59 | elseif( CMAKE_C_COMPILER_ID STREQUAL "Intel" ) 60 | 61 | # detect unused variables 62 | # string( APPEND MY_CMAKE_C_FLAGS " -Wunused-variable" ) 63 | 64 | endif() 65 | 66 | # overwrite compiler flags 67 | set( 68 | CMAKE_C_FLAGS_DEBUG ${MY_CMAKE_C_FLAGS} 69 | CACHE STRING "Flags used by the compiler during debug builds." FORCE 70 | ) 71 | 72 | endif() 73 | 74 | 75 | ################################# 76 | # Compiler Flags (Release Mode) # 77 | ################################# 78 | 79 | # set release compiler flags 80 | if( CMAKE_BUILD_TYPE STREQUAL "Release" ) 81 | 82 | # enable optimization 83 | string( APPEND MY_CMAKE_C_FLAGS " -O3" ) 84 | 85 | if( CMAKE_C_COMPILER_ID STREQUAL "GNU" ) 86 | 87 | # detect unused variables 88 | # string( APPEND MY_CMAKE_C_FLAGS " -Wunused-variable" ) 89 | 90 | elseif( CMAKE_C_COMPILER_ID STREQUAL "Intel" ) 91 | 92 | # detect unused variables 93 | # string( APPEND MY_CMAKE_C_FLAGS " -Wunused-variable" ) 94 | 95 | endif() 96 | 97 | # overwrite compiler flags 98 | set( 99 | CMAKE_C_FLAGS_RELEASE ${MY_CMAKE_C_FLAGS} 100 | CACHE STRING "Flags used by the compiler during debug builds." FORCE 101 | ) 102 | 103 | endif() 104 | 105 | -------------------------------------------------------------------------------- /share/cmake/directories.cmake: -------------------------------------------------------------------------------- 1 | set( SRC ${CMAKE_SOURCE_DIR}/src ) 2 | set( INC ${CMAKE_SOURCE_DIR}/include ) 3 | set( LIB ${CMAKE_SOURCE_DIR}/lib ) 4 | set( BIN ${CMAKE_SOURCE_DIR}/bin ) 5 | 6 | # Define relative module path 7 | string( LENGTH ${CMAKE_SOURCE_DIR} CMAKE_SOURCE_DIR_LEN ) 8 | 9 | -------------------------------------------------------------------------------- /share/files/comment_test.para: -------------------------------------------------------------------------------- 1 | # This is a comment 2 | 3 | This is not a comment 4 | 5 | 6 | This!## is a comment 7 | -------------------------------------------------------------------------------- /share/files/example.para: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------- 2 | # TMESH 3 | #----------------------------------------------------------- 4 | Global element size: 0.5 5 | Number of quadtree elements: 50 6 | Mesh bounding box: -10.0, -10.0, 20.0, 20.0 7 | 8 | 9 | #----------------------------------------------------------- 10 | # NODES 11 | #----------------------------------------------------------- 12 | Define nodes: 13 | 1.0, 1.0 14 | 10.0, 0.0 15 | 10.0, 10.0 16 | 0.0, 10.0 17 | 2.0, 2.0 18 | 2.0, 4.0 19 | 4.0, 4.0 20 | 4.0, 2.0 21 | 6.0, 5.0 22 | 7.0, 7.0 23 | 9.0, 4.0 24 | End nodes 25 | 26 | #----------------------------------------------------------- 27 | # BOUNDARIES 28 | #----------------------------------------------------------- 29 | # For every boundary an integer is assigned as marker. 30 | # Boundary edges are defined by: 31 | # 32 | # iStart, iEnd, edgeMarker, edgeRefinement 33 | # 34 | # > iStart and iEnd corresponds to the indices of the 35 | # nodes define above 36 | # > edgeMarker is an integer that is assigned to the 37 | # respective edge 38 | # > edgeRefinement is a double used to control the local 39 | # refinement near share edges (>0) 40 | # 41 | # > Exterior boundaries must be defined counter-clockwise 42 | # > Interior boundaries must be defined clockwise 43 | # 44 | #----------------------------------------------------------- 45 | Define exterior boundary: 1 46 | 0, 1, 1, 1.4 47 | 1, 2, 1, 1.4 48 | 2, 3, 1, 1.4 49 | 3, 0, 1, 1.4 50 | End exterior boundary 51 | 52 | Define interior boundary: 1 53 | 4, 5, 2, 1.6 54 | 5, 6, 2, 1.6 55 | 6, 7, 2, 1.6 56 | 7, 4, 2, 1.6 57 | End interior boundary 58 | 59 | Define interior boundary: 2 60 | 8, 9, 3, 1.5 61 | 9, 10, 3, 1.5 62 | 10, 8, 3, 1.5 63 | End interior boundary 64 | -------------------------------------------------------------------------------- /share/files/simple.para: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------- 2 | # TMESH 3 | #----------------------------------------------------------- 4 | Global element size: 0.5 5 | Number of quadtree elements: 50 6 | Mesh bounding box: -10.0, -10.0, 20.0, 20.0 7 | Output format: STDOUT 8 | 9 | 10 | #----------------------------------------------------------- 11 | # NODES 12 | #----------------------------------------------------------- 13 | Define nodes: 14 | 1.0, 1.0 15 | 8.0, 0.0 16 | 5.0, 10.0 17 | 0.0, 10.0 18 | End nodes 19 | 20 | #----------------------------------------------------------- 21 | # BOUNDARIES 22 | #----------------------------------------------------------- 23 | Define exterior boundary: 1 24 | 0, 1, 0, 1.4 25 | 1, 2, 0, 0.4 26 | 2, 3, 0, 0.4 27 | 3, 0, 0, 0.4 28 | End exterior boundary 29 | 30 | -------------------------------------------------------------------------------- /share/files/size_function.para: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------- 2 | # TMESH 3 | #----------------------------------------------------------- 4 | Global element size: 0.5 5 | Number of quadtree elements: 50 6 | Mesh bounding box: -10.0, -10.0, 20.0, 20.0 7 | Size function: 0.5-0.43*exp(-0.03*((1.-x)*(2.-x)+(9.-y)*(9.-y))) 8 | 9 | #----------------------------------------------------------- 10 | # NODES 11 | #----------------------------------------------------------- 12 | Define nodes: 13 | 1.0, 1.0 14 | 10.0, 0.0 15 | 10.0, 10.0 16 | 0.0, 10.0 17 | 2.0, 2.0 18 | 2.0, 4.0 19 | 4.0, 4.0 20 | 4.0, 2.0 21 | 6.0, 5.0 22 | 7.0, 7.0 23 | 9.0, 4.0 24 | End nodes 25 | 26 | #----------------------------------------------------------- 27 | # BOUNDARIES 28 | #----------------------------------------------------------- 29 | # For every boundary an integer is assigned as marker. 30 | # Boundary edges are defined by: 31 | # 32 | # iStart, iEnd, edgeMarker, edgeRefinement 33 | # 34 | # > iStart and iEnd corresponds to the indices of the 35 | # nodes define above 36 | # > edgeMarker is an integer that is assigned to the 37 | # respective edge 38 | # > edgeRefinement is a double used to control the local 39 | # refinement near share edges (>0) 40 | # 41 | # > Exterior boundaries must be defined counter-clockwise 42 | # > Interior boundaries must be defined clockwise 43 | # 44 | #----------------------------------------------------------- 45 | Define exterior boundary: 1 46 | 0, 1, 0, 1.4 47 | 1, 2, 0, 1.4 48 | 2, 3, 0, 1.4 49 | 3, 0, 0, 1.4 50 | End exterior boundary 51 | 52 | Define interior boundary: 1 53 | 4, 5, 1, 1.6 54 | 5, 6, 1, 1.6 55 | 6, 7, 1, 1.6 56 | 7, 4, 1, 1.6 57 | End interior boundary 58 | 59 | Define interior boundary: 2 60 | 8, 9, 2, 1.5 61 | 9, 10, 2, 1.5 62 | 10, 8, 2, 1.5 63 | End interior boundary 64 | -------------------------------------------------------------------------------- /share/files/square.para: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------- 2 | # TMESH 3 | #----------------------------------------------------------- 4 | Global element size: 0.5 5 | Number of quadtree elements: 50 6 | Mesh bounding box: -10.0, -10.0, 20.0, 20.0 7 | Output format: STDOUT 8 | 9 | 10 | #----------------------------------------------------------- 11 | # NODES 12 | #----------------------------------------------------------- 13 | Define nodes: 14 | 0.0, 0.0 15 | 1.0, 0.0 16 | 1.0, 1.0 17 | 0.0, 1.0 18 | End nodes 19 | 20 | #----------------------------------------------------------- 21 | # BOUNDARIES 22 | #----------------------------------------------------------- 23 | Define exterior boundary: 1 24 | 0, 1, 1, 1.4 25 | 1, 2, 2, 1.4 26 | 2, 3, 3, 1.4 27 | 3, 0, 4, 1.4 28 | End exterior boundary 29 | 30 | -------------------------------------------------------------------------------- /share/python/performance.py: -------------------------------------------------------------------------------- 1 | from matplotlib import pyplot as plt 2 | import numpy as np 3 | import sys, os 4 | 5 | 6 | 7 | def main(): 8 | if len(sys.argv) < 2: 9 | print("performanc.py ") 10 | sys.exit(1) 11 | 12 | export_path = sys.argv[1] 13 | 14 | log_line = lambda x, Px, Py, n: (x**n) * np.exp(np.log(Py) - n * np.log(Px)) 15 | 16 | # Performance with old version (bubble sort & other things) 17 | N0 = np.array([46, 534, 2164, 8592]) 18 | T0 = np.array([2.25e-03, 1.12e-01, 2.01e+00, 4.14e+01]) 19 | # Performance with version 0.2 20 | N1 = np.array([29, 106, 464, 1940, 11396, 45842, 184070, 1055218, 4221754]) 21 | T1 = np.array([7.22e-04, 2.88e-03, 6.56e-03, 3.44e-02, 1.48e-01, 5.76e-01, 2.90e+00, 2.03e+01, 9.13e+01]) 22 | # Performance with version 0.3 - automatic size function 23 | N2 = np.array([30, 95, 233, 1251, 4407, 81480, 238947, 1109863, 1808235,4293213]) 24 | T2 = np.array([1.653000e-03, 1.732000e-03 ,5.852000e-03, 3.76e-02, 9.34e-02, 1.708676e+00, 5.747154e+00, 2.633492e+01, 4.615543e+01, 1.089948e+02]) 25 | 26 | log_1 = log_line(N1, 5e-2, 2e-6, 1) 27 | #log_2 = log_line(N, 5e-2, 1e-9, 2) 28 | 29 | fig, ax = plt.subplots(1,1,figsize=(5,3)) 30 | #ax.plot(N0, T0, c=(.5,.5,.9), ls='-', marker='o', lw=2.0, label='tMesh - v0.1') 31 | ax.plot(N1, T1, c=(.3,.3,.9), ls='-', marker='o', lw=2.0, label='Mesh A') 32 | ax.plot(N2, T2, c=(.9,.3,.9), ls='-', marker='o', lw=2.0, label='Mesh B') 33 | 34 | ax.plot(N1, log_1, c=(.1,.1,.1), ls='--', label='$\mathcal{O}(N)$') 35 | #ax.plot(N, log_2, c=(.5,.5,.5), ls='--', label='$\mathcal{O}(N^2)$') 36 | 37 | ax.legend() 38 | 39 | ax.set_yscale('log') 40 | ax.set_xscale('log') 41 | 42 | ax.set_xlabel('Number of triangles') 43 | ax.set_ylabel('Meshing time in seconds') 44 | 45 | #ax.grid(True) 46 | 47 | fig_path = os.path.join( export_path, 'performance') 48 | print("Exporting {:}".format(fig_path)) 49 | plt.tight_layout() 50 | fig.savefig(fig_path + '.png', dpi=280) 51 | plt.close(fig) 52 | print("Done") 53 | 54 | 55 | if __name__ == '__main__': main() 56 | -------------------------------------------------------------------------------- /share/python/plot_boundary.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Small function to plot the mesh boundaries 3 | 4 | 5 | 6 | ''' 7 | from matplotlib import pyplot as plt 8 | import numpy as np 9 | import sys 10 | 11 | def read_meshdata(mesh_file): 12 | ''' 13 | Function to read the raw mesh data 14 | ''' 15 | with open(mesh_file, 'r') as reader: 16 | lines = reader.readlines() 17 | n_nodes = int(lines[0].split(' ')[1]) 18 | 19 | nodes = np.zeros( (n_nodes, 2) ) 20 | boundaries = {} 21 | 22 | for i in range(1, n_nodes+1): 23 | line = lines[i].replace('\n','').split('\t') 24 | nodes[i-1][0] = float(line[1]) 25 | nodes[i-1][1] = float(line[2]) 26 | 27 | lines = lines[n_nodes+1:] 28 | while (lines[0].split(' ')[0] == 'BOUNDARY'): 29 | 30 | boundary = int(lines[0].split(' ')[1]) 31 | n_edges = int(lines[0].split(' ')[2]) 32 | edges = [] 33 | boundaries.update({ boundary : edges }) 34 | 35 | for i in range(1, n_edges+1): 36 | line = lines[i].replace('\n','').split('\t') 37 | edge = (int(line[1]), int(line[2])) 38 | edges.append(edge) 39 | 40 | lines = lines[n_edges+1] 41 | 42 | return nodes, boundaries 43 | 44 | 45 | def main(): 46 | ''' The main function ''' 47 | if len(sys.argv) < 2: 48 | print("plot_boundary.py .dat") 49 | sys.exit(1) 50 | 51 | nodes, boundaries = read_meshdata(sys.argv[1]) 52 | 53 | 54 | fig, ax = plt.subplots(1,1,figsize=(10,10)) 55 | 56 | for i_bdry, edges in boundaries.items(): 57 | for e in edges: 58 | ax.plot(nodes[e,0], nodes[e,1], c='k', 59 | lw=2.0, ls='-',marker='o') 60 | 61 | 62 | plt.show() 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | if __name__ == '__main__': main() 75 | -------------------------------------------------------------------------------- /share/python/plot_mesh.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Small function to plot the mesh boundaries 3 | 4 | 5 | 6 | ''' 7 | from matplotlib import pyplot as plt 8 | from matplotlib.patches import Polygon 9 | from matplotlib.collections import PatchCollection 10 | import numpy as np 11 | import sys, os 12 | 13 | TRI_PATCH = {'edgecolors' : ['k'], 14 | 'linewidths' : 0.9, 15 | 'facecolors' : ['w'], 16 | 'joinstyle' : 'round', 17 | 'capstyle' : 'round', 18 | 'alpha' : 1.0, 19 | 'cmap' : 'coolwarm'} 20 | 21 | def read_meshdata(mesh_file, read_front=False): 22 | ''' 23 | Function to read the raw mesh data 24 | ''' 25 | with open(mesh_file, 'r') as reader: 26 | lines = reader.readlines() 27 | 28 | # Filter out comments 29 | for i in range(len(lines)-1, -1, -1): 30 | identifier = lines[i].split(' ')[0] 31 | if (identifier == '>'): 32 | lines.pop(i) 33 | 34 | n_nodes = int(lines[0].split(' ')[1]) 35 | 36 | nodes = np.zeros( (n_nodes, 2) ) 37 | boundaries = {} 38 | bdry_marker = {} 39 | front_edges = [] 40 | tris = [] 41 | 42 | # Get node coordinates 43 | #---------------------------------------------------- 44 | for i in range(1, n_nodes+1): 45 | line = lines[i].replace('\n','').split('\t') 46 | nodes[i-1][0] = float(line[1]) 47 | nodes[i-1][1] = float(line[2]) 48 | 49 | # Get boundary data 50 | #---------------------------------------------------- 51 | lines = lines[n_nodes+1:] 52 | while (lines[0].split(' ')[0] == 'BOUNDARY'): 53 | 54 | boundary = int(lines[0].split(' ')[1]) 55 | n_bdry_edges = int(lines[0].split(' ')[2]) 56 | edges = [] 57 | boundaries.update({ boundary : edges }) 58 | 59 | for i in range(1, n_bdry_edges+1): 60 | line = lines[i].replace('\n','').split('\t') 61 | edge = (int(line[1]), int(line[2])) 62 | marker = int(line[3]) 63 | edges.append(edge) 64 | 65 | if (marker in bdry_marker.keys()): 66 | bdry_marker[marker].append(edge) 67 | else: 68 | bdry_marker.update({marker : [edge]}) 69 | 70 | lines = lines[n_bdry_edges+1:] 71 | 72 | # Get advancing front data 73 | #---------------------------------------------------- 74 | if read_front: 75 | n_front_edges = int(lines[0].split(' ')[1]) 76 | 77 | for i in range(1, n_front_edges+1): 78 | line = lines[i].replace('\n','').split('\t') 79 | edge = (int(line[1]), int(line[2])) 80 | front_edges.append(edge) 81 | 82 | lines = lines[n_front_edges+1:] 83 | 84 | # Get triangle data 85 | #---------------------------------------------------- 86 | n_tris = int(lines[0].split(' ')[1]) 87 | 88 | for i in range(1, n_tris+1): 89 | line = lines[i].replace('\n','').split('\t') 90 | tri = (int(line[1]), int(line[2]), int(line[3])) 91 | tris.append(tri) 92 | 93 | 94 | return nodes, boundaries, bdry_marker, front_edges, tris 95 | 96 | 97 | def main(): 98 | ''' The main function ''' 99 | if len(sys.argv) < 3: 100 | print("plot_boundary.py ") 101 | sys.exit(1) 102 | 103 | nodes, boundaries, bdry_marker, front_edges, tris = read_meshdata(sys.argv[1]) 104 | export_path = sys.argv[2] 105 | 106 | i_plts = 0 107 | 108 | for step in range(len(tris), len(tris)-1-i_plts, -1): 109 | 110 | fig, ax = plt.subplots(1,1,figsize=(8,4)) 111 | ax.set_aspect('equal') 112 | 113 | #for i_bdry, edges in boundaries.items(): 114 | # for e in edges: 115 | # ax.plot(nodes[e,0], nodes[e,1], c='k', 116 | # lw=2.0, ls='-',marker='o') 117 | 118 | #for i, n in enumerate(nodes): 119 | #ax.plot(nodes[i,0], nodes[i,1], marker='o', c='k', ms=4) 120 | #ax.text(n[0],n[1],i, color='b') 121 | 122 | if step == len(tris): 123 | for e in front_edges: 124 | ax.plot(nodes[e,0], nodes[e,1], c='r', 125 | lw=1.0, ls='-') #,marker='o') 126 | 127 | tri_patches = [] 128 | for i_tri, tri in enumerate(tris[:step]): 129 | tri_patches.append(Polygon([nodes[tri[i]] for i in range(3)])) 130 | #tri_centr = np.mean([nodes[tri[i]] for i in range(3)], axis=0) 131 | #ax.text(tri_centr[0], tri_centr[1], i_tri, color='k') 132 | 133 | tri_col = PatchCollection(tri_patches, **TRI_PATCH) 134 | ax.add_collection(tri_col) 135 | 136 | ax.set_xlim((nodes[:,0].min(),nodes[:,0].max())) 137 | ax.set_ylim((nodes[:,1].min(),nodes[:,1].max())) 138 | ax.set_axis_off() 139 | 140 | if i_plts > 0: 141 | fig_path = export_path + '_{:}'.format(len(tris)-step) 142 | else: 143 | fig_path = export_path 144 | 145 | if ( fig_path[-4:] != '.png' ): 146 | fig_path += '.png' 147 | 148 | print("Exporting {:}".format(fig_path)) 149 | plt.tight_layout() 150 | fig.savefig(fig_path, dpi=280, transparent=True) 151 | plt.close(fig) 152 | print("Done") 153 | 154 | 155 | 156 | 157 | if __name__ == '__main__': main() 158 | -------------------------------------------------------------------------------- /share/python/plot_qtree.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Small function to plot a quadtree structure 3 | 4 | 5 | 6 | ''' 7 | 8 | from matplotlib.ticker import MaxNLocator 9 | from matplotlib.colors import BoundaryNorm 10 | from mpl_toolkits.axes_grid1 import make_axes_locatable 11 | 12 | from matplotlib import pyplot as plt 13 | from matplotlib.patches import Rectangle 14 | from matplotlib.collections import PatchCollection 15 | import numpy as np 16 | import sys, os 17 | 18 | QUAD_PATCH = {'edgecolors' : ['k'], 19 | 'linewidths' : 0.5, 20 | 'facecolors' : ['None'], 21 | 'joinstyle' : 'round', 22 | 'capstyle' : 'round', 23 | 'alpha' : 1.0, 24 | 'cmap' : 'Greys'} 25 | 26 | def read_quaddata(mesh_file): 27 | ''' 28 | Function to read the raw quadtree data 29 | ''' 30 | with open(mesh_file, 'r') as reader: 31 | lines = reader.readlines() 32 | 33 | # Filter out comments 34 | for i in range(len(lines)-1, -1, -1): 35 | identifier = lines[i].split(' ')[0] 36 | if (identifier == '>'): 37 | lines.pop(i) 38 | 39 | quads = [] 40 | layers = [] 41 | 42 | # Get quad coordinates 43 | #---------------------------------------------------- 44 | for line in lines: 45 | cur_line = line.replace('\n','').split('\t') 46 | layer = int(cur_line[0]) 47 | x_min = float(cur_line[1]) 48 | y_min = float(cur_line[2]) 49 | x_max = float(cur_line[3]) 50 | y_max = float(cur_line[4]) 51 | quads.append( [(x_min, y_min), (x_max, y_max)] ) 52 | layers.append(layer) 53 | 54 | return np.array(quads), np.array(layers) 55 | 56 | def main(): 57 | ''' The main function ''' 58 | if len(sys.argv) < 3: 59 | print("plot_qtree.py .dat ") 60 | sys.exit(1) 61 | 62 | quads, layers = read_quaddata(sys.argv[1]) 63 | export_path = sys.argv[2] 64 | 65 | fig, ax = plt.subplots(1,1,figsize=(24,18)) 66 | ax.set_aspect('equal') 67 | 68 | quad_patches = [] 69 | for i, q in enumerate(quads): 70 | width = q[1][0] - q[0][0] 71 | height = q[1][1] - q[0][1] 72 | quad_patches.append(Rectangle(q[0], width, height)) 73 | 74 | ''' 75 | # Add colormap for layers 76 | # --------------------------------- 77 | cmap = plt.get_cmap(QUAD_PATCH['cmap']) 78 | levels = MaxNLocator(nbins=25).tick_values(layers.min(), 79 | layers.max()) 80 | norm = BoundaryNorm(levels, ncolors=cmap.N, clip=True) 81 | QUAD_PATCH.update({'norm':norm}) 82 | ''' 83 | 84 | quad_col = PatchCollection(quad_patches, **QUAD_PATCH) 85 | # quad_col.set_array(layers) 86 | ax.add_collection(quad_col) 87 | 88 | ax.set_xlim(( quads[:,0][:,0].min(), quads[:,1][:,0].max()) ) 89 | ax.set_ylim(( quads[:,0][:,1].min(), quads[:,1][:,1].max()) ) 90 | ax.set_axis_off() 91 | 92 | fig_path = os.path.join( export_path, 'qtree') 93 | print("Exporting {:}".format(fig_path)) 94 | plt.tight_layout() 95 | fig.savefig(fig_path + '.png', dpi=300) 96 | plt.close(fig) 97 | print("Done") 98 | 99 | if __name__ == '__main__': main() 100 | -------------------------------------------------------------------------------- /share/python/spiral.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from matplotlib import pyplot as plt 3 | from numpy import pi, sin, cos 4 | 5 | 6 | def main(): 7 | 8 | a = 2.5 9 | b = -3.4 10 | c = 6.5 11 | t = np.linspace(0.0, 5.*pi, 5000) 12 | x = (a + b * t) * cos(t) + c * sin(40*t) 13 | y = (a + b * t) * sin(t) + c * cos(40*t) 14 | fig, ax = plt.subplots(1,1,figsize=(10,10)) 15 | ax.plot(x,y,lw=2.,c='r',ls='',marker='x') 16 | ax.set_xlim([-50,55]) 17 | ax.set_ylim([-55,50]) 18 | plt.show() 19 | 20 | if __name__ == '__main__': main() 21 | -------------------------------------------------------------------------------- /src/tmesh/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ############################################################## 2 | # MODULE: LEARN C THE HARD WAY 3 | ############################################################## 4 | # Define directories 5 | set( TMESH_DIR ${SRC}/tmesh ) 6 | set( TMESH_INC ${TMESH_DIR}/include ) 7 | set( TMESH_SRC ${TMESH_DIR}/src ) 8 | 9 | # Define source files 10 | set( TMESH_MAIN 11 | ${TMESH_SRC}/bstrlib.c 12 | ${TMESH_SRC}/tinyexpr.c 13 | ${TMESH_SRC}/tmParam.c 14 | ${TMESH_SRC}/tmList.c 15 | ${TMESH_SRC}/tmNode.c 16 | ${TMESH_SRC}/tmEdge.c 17 | ${TMESH_SRC}/tmTri.c 18 | ${TMESH_SRC}/tmBdry.c 19 | ${TMESH_SRC}/tmFront.c 20 | ${TMESH_SRC}/tmMesh.c 21 | ${TMESH_SRC}/tmQtree.c 22 | ) 23 | 24 | ############################################################## 25 | # LIBRARY: tmesh 26 | ############################################################## 27 | # define name 28 | set( TMESH_LIB tmesh ) 29 | 30 | # add sources to library 31 | add_library( ${TMESH_LIB} STATIC ${TMESH_MAIN} ) 32 | #add_library( ${TMESH_LIB} SHARED ${TMESH_MAIN} ) 33 | 34 | # set public include 35 | target_include_directories( ${TMESH_LIB} PUBLIC 36 | $ 37 | PRIVATE ${TMESH_SRC} 38 | ) 39 | 40 | target_link_libraries( ${TMESH_LIB} 41 | m 42 | ) 43 | 44 | install( TARGETS tmesh DESTINATION ${LIB} ) 45 | 46 | ############################################################## 47 | # MAIN: tmesh 48 | ############################################################## 49 | set( MAINEXE_TMESH TMesh ) 50 | 51 | add_executable( ${MAINEXE_TMESH} 52 | ${TMESH_SRC}/main.c 53 | ) 54 | 55 | target_include_directories( ${MAINEXE_TMESH} PUBLIC 56 | $ 57 | ) 58 | 59 | target_link_libraries( ${MAINEXE_TMESH} 60 | tmesh 61 | m 62 | ) 63 | 64 | # Install executables 65 | install( TARGETS ${MAINEXE_TMESH} RUNTIME DESTINATION ${BIN} ) 66 | 67 | 68 | ############################################################## 69 | # TESTS: tmesh 70 | ############################################################## 71 | set( TESTEXE_TMESH tmesh_test ) 72 | set( TESTDIR_TMESH ${TMESH_DIR}/test ) 73 | 74 | add_executable( ${TESTEXE_TMESH} 75 | ${TESTDIR_TMESH}/tmList_tests.c 76 | ${TESTDIR_TMESH}/tmParam_tests.c 77 | ${TESTDIR_TMESH}/tmesh_tests.c 78 | ${TESTDIR_TMESH}/tmesh_cylinder.c 79 | ${TESTDIR_TMESH}/tmesh_examples.c 80 | ${TESTDIR_TMESH}/geom_tests.c 81 | ${TESTDIR_TMESH}/unit_tests.c 82 | ) 83 | 84 | target_include_directories( ${TESTEXE_TMESH} PUBLIC 85 | $ 86 | ) 87 | 88 | target_link_libraries( ${TESTEXE_TMESH} 89 | tmesh 90 | m 91 | ) 92 | 93 | # Install executables 94 | install( TARGETS ${TESTEXE_TMESH} RUNTIME DESTINATION ${BIN} ) 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /src/tmesh/include/tmesh/bstrlib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This source file is part of the bstring string library. This code was 3 | * written by Paul Hsieh in 2002-2015, and is covered by the BSD open source 4 | * license and the GPL. Refer to the accompanying documentation for details 5 | * on usage and license. 6 | */ 7 | 8 | /* 9 | * bstrlib.h 10 | * 11 | * This file is the interface for the core bstring functions. 12 | */ 13 | 14 | #ifndef BSTRLIB_INCLUDE 15 | #define BSTRLIB_INCLUDE 16 | 17 | #ifdef __cplusplus 18 | extern "C" { 19 | #endif 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #if !defined (BSTRLIB_VSNP_OK) && !defined (BSTRLIB_NOVSNP) 27 | # if defined (__TURBOC__) && !defined (__BORLANDC__) 28 | # define BSTRLIB_NOVSNP 29 | # endif 30 | #endif 31 | 32 | #define BSTR_ERR (-1) 33 | #define BSTR_OK (0) 34 | #define BSTR_BS_BUFF_LENGTH_GET (0) 35 | 36 | typedef struct tagbstring * bstring; 37 | typedef const struct tagbstring * const_bstring; 38 | 39 | /* Version */ 40 | #define BSTR_VER_MAJOR 1 41 | #define BSTR_VER_MINOR 0 42 | #define BSTR_VER_UPDATE 0 43 | 44 | /* Copy functions */ 45 | #define cstr2bstr bfromcstr 46 | extern bstring bfromcstr (const char * str); 47 | extern bstring bfromcstralloc (int mlen, const char * str); 48 | extern bstring bfromcstrrangealloc (int minl, int maxl, const char* str); 49 | extern bstring blk2bstr (const void * blk, int len); 50 | extern char * bstr2cstr (const_bstring s, char z); 51 | extern int bcstrfree (char * s); 52 | extern bstring bstrcpy (const_bstring b1); 53 | extern int bassign (bstring a, const_bstring b); 54 | extern int bassignmidstr (bstring a, const_bstring b, int left, int len); 55 | extern int bassigncstr (bstring a, const char * str); 56 | extern int bassignblk (bstring a, const void * s, int len); 57 | 58 | /* Destroy function */ 59 | extern int bdestroy (bstring b); 60 | 61 | /* Space allocation hinting functions */ 62 | extern int balloc (bstring s, int len); 63 | extern int ballocmin (bstring b, int len); 64 | 65 | /* Substring extraction */ 66 | extern bstring bmidstr (const_bstring b, int left, int len); 67 | 68 | /* Various standard manipulations */ 69 | extern int bconcat (bstring b0, const_bstring b1); 70 | extern int bconchar (bstring b0, char c); 71 | extern int bcatcstr (bstring b, const char * s); 72 | extern int bcatblk (bstring b, const void * s, int len); 73 | extern int binsert (bstring s1, int pos, const_bstring s2, unsigned char fill); 74 | extern int binsertblk (bstring s1, int pos, const void * s2, int len, unsigned char fill); 75 | extern int binsertch (bstring s1, int pos, int len, unsigned char fill); 76 | extern int breplace (bstring b1, int pos, int len, const_bstring b2, unsigned char fill); 77 | extern int bdelete (bstring s1, int pos, int len); 78 | extern int bsetstr (bstring b0, int pos, const_bstring b1, unsigned char fill); 79 | extern int btrunc (bstring b, int n); 80 | 81 | /* Scan/search functions */ 82 | extern int bstricmp (const_bstring b0, const_bstring b1); 83 | extern int bstrnicmp (const_bstring b0, const_bstring b1, int n); 84 | extern int biseqcaseless (const_bstring b0, const_bstring b1); 85 | extern int biseqcaselessblk (const_bstring b, const void * blk, int len); 86 | extern int bisstemeqcaselessblk (const_bstring b0, const void * blk, int len); 87 | extern int biseq (const_bstring b0, const_bstring b1); 88 | extern int biseqblk (const_bstring b, const void * blk, int len); 89 | extern int bisstemeqblk (const_bstring b0, const void * blk, int len); 90 | extern int biseqcstr (const_bstring b, const char * s); 91 | extern int biseqcstrcaseless (const_bstring b, const char * s); 92 | extern int bstrcmp (const_bstring b0, const_bstring b1); 93 | extern int bstrncmp (const_bstring b0, const_bstring b1, int n); 94 | extern int binstr (const_bstring s1, int pos, const_bstring s2); 95 | extern int binstrr (const_bstring s1, int pos, const_bstring s2); 96 | extern int binstrcaseless (const_bstring s1, int pos, const_bstring s2); 97 | extern int binstrrcaseless (const_bstring s1, int pos, const_bstring s2); 98 | extern int bstrchrp (const_bstring b, int c, int pos); 99 | extern int bstrrchrp (const_bstring b, int c, int pos); 100 | #define bstrchr(b,c) bstrchrp ((b), (c), 0) 101 | #define bstrrchr(b,c) bstrrchrp ((b), (c), blength(b)-1) 102 | extern int binchr (const_bstring b0, int pos, const_bstring b1); 103 | extern int binchrr (const_bstring b0, int pos, const_bstring b1); 104 | extern int bninchr (const_bstring b0, int pos, const_bstring b1); 105 | extern int bninchrr (const_bstring b0, int pos, const_bstring b1); 106 | extern int bfindreplace (bstring b, const_bstring find, const_bstring repl, int pos); 107 | extern int bfindreplacecaseless (bstring b, const_bstring find, const_bstring repl, int pos); 108 | 109 | /* List of string container functions */ 110 | struct bstrList { 111 | int qty, mlen; 112 | bstring * entry; 113 | }; 114 | extern struct bstrList * bstrListCreate (void); 115 | extern int bstrListDestroy (struct bstrList * sl); 116 | extern int bstrListAlloc (struct bstrList * sl, int msz); 117 | extern int bstrListAllocMin (struct bstrList * sl, int msz); 118 | 119 | /* String split and join functions */ 120 | extern struct bstrList * bsplit (const_bstring str, unsigned char splitChar); 121 | extern struct bstrList * bsplits (const_bstring str, const_bstring splitStr); 122 | extern struct bstrList * bsplitstr (const_bstring str, const_bstring splitStr); 123 | extern bstring bjoin (const struct bstrList * bl, const_bstring sep); 124 | extern bstring bjoinblk (const struct bstrList * bl, const void * s, int len); 125 | extern int bsplitcb (const_bstring str, unsigned char splitChar, int pos, 126 | int (* cb) (void * parm, int ofs, int len), void * parm); 127 | extern int bsplitscb (const_bstring str, const_bstring splitStr, int pos, 128 | int (* cb) (void * parm, int ofs, int len), void * parm); 129 | extern int bsplitstrcb (const_bstring str, const_bstring splitStr, int pos, 130 | int (* cb) (void * parm, int ofs, int len), void * parm); 131 | 132 | /* Miscellaneous functions */ 133 | extern int bpattern (bstring b, int len); 134 | extern int btoupper (bstring b); 135 | extern int btolower (bstring b); 136 | extern int bltrimws (bstring b); 137 | extern int brtrimws (bstring b); 138 | extern int btrimws (bstring b); 139 | 140 | #if !defined (BSTRLIB_NOVSNP) 141 | extern bstring bformat (const char * fmt, ...); 142 | extern int bformata (bstring b, const char * fmt, ...); 143 | extern int bassignformat (bstring b, const char * fmt, ...); 144 | extern int bvcformata (bstring b, int count, const char * fmt, va_list arglist); 145 | 146 | #define bvformata(ret, b, fmt, lastarg) { \ 147 | bstring bstrtmp_b = (b); \ 148 | const char * bstrtmp_fmt = (fmt); \ 149 | int bstrtmp_r = BSTR_ERR, bstrtmp_sz = 16; \ 150 | for (;;) { \ 151 | va_list bstrtmp_arglist; \ 152 | va_start (bstrtmp_arglist, lastarg); \ 153 | bstrtmp_r = bvcformata (bstrtmp_b, bstrtmp_sz, bstrtmp_fmt, bstrtmp_arglist); \ 154 | va_end (bstrtmp_arglist); \ 155 | if (bstrtmp_r >= 0) { /* Everything went ok */ \ 156 | bstrtmp_r = BSTR_OK; \ 157 | break; \ 158 | } else if (-bstrtmp_r <= bstrtmp_sz) { /* A real error? */ \ 159 | bstrtmp_r = BSTR_ERR; \ 160 | break; \ 161 | } \ 162 | bstrtmp_sz = -bstrtmp_r; /* Doubled or target size */ \ 163 | } \ 164 | ret = bstrtmp_r; \ 165 | } 166 | 167 | #endif 168 | 169 | typedef int (*bNgetc) (void *parm); 170 | typedef size_t (* bNread) (void *buff, size_t elsize, size_t nelem, void *parm); 171 | 172 | /* Input functions */ 173 | extern bstring bgets (bNgetc getcPtr, void * parm, char terminator); 174 | extern bstring bread (bNread readPtr, void * parm); 175 | extern int bgetsa (bstring b, bNgetc getcPtr, void * parm, char terminator); 176 | extern int bassigngets (bstring b, bNgetc getcPtr, void * parm, char terminator); 177 | extern int breada (bstring b, bNread readPtr, void * parm); 178 | 179 | /* Stream functions */ 180 | extern struct bStream * bsopen (bNread readPtr, void * parm); 181 | extern void * bsclose (struct bStream * s); 182 | extern int bsbufflength (struct bStream * s, int sz); 183 | extern int bsreadln (bstring b, struct bStream * s, char terminator); 184 | extern int bsreadlns (bstring r, struct bStream * s, const_bstring term); 185 | extern int bsread (bstring b, struct bStream * s, int n); 186 | extern int bsreadlna (bstring b, struct bStream * s, char terminator); 187 | extern int bsreadlnsa (bstring r, struct bStream * s, const_bstring term); 188 | extern int bsreada (bstring b, struct bStream * s, int n); 189 | extern int bsunread (struct bStream * s, const_bstring b); 190 | extern int bspeek (bstring r, const struct bStream * s); 191 | extern int bssplitscb (struct bStream * s, const_bstring splitStr, 192 | int (* cb) (void * parm, int ofs, const_bstring entry), void * parm); 193 | extern int bssplitstrcb (struct bStream * s, const_bstring splitStr, 194 | int (* cb) (void * parm, int ofs, const_bstring entry), void * parm); 195 | extern int bseof (const struct bStream * s); 196 | 197 | struct tagbstring { 198 | int mlen; 199 | int slen; 200 | unsigned char * data; 201 | }; 202 | 203 | /* Accessor macros */ 204 | #define blengthe(b, e) (((b) == (void *)0 || (b)->slen < 0) ? (int)(e) : ((b)->slen)) 205 | #define blength(b) (blengthe ((b), 0)) 206 | #define bdataofse(b, o, e) (((b) == (void *)0 || (b)->data == (void*)0) ? (char *)(e) : ((char *)(b)->data) + (o)) 207 | #define bdataofs(b, o) (bdataofse ((b), (o), (void *)0)) 208 | #define bdatae(b, e) (bdataofse (b, 0, e)) 209 | #define bdata(b) (bdataofs (b, 0)) 210 | #define bchare(b, p, e) ((((unsigned)(p)) < (unsigned)blength(b)) ? ((b)->data[(p)]) : (e)) 211 | #define bchar(b, p) bchare ((b), (p), '\0') 212 | 213 | /* Static constant string initialization macro */ 214 | #define bsStaticMlen(q,m) {(m), (int) sizeof(q)-1, (unsigned char *) ("" q "")} 215 | #if defined(_MSC_VER) 216 | # define bsStatic(q) bsStaticMlen(q,-32) 217 | #endif 218 | #ifndef bsStatic 219 | # define bsStatic(q) bsStaticMlen(q,-__LINE__) 220 | #endif 221 | 222 | /* Static constant block parameter pair */ 223 | #define bsStaticBlkParms(q) ((void *)("" q "")), ((int) sizeof(q)-1) 224 | 225 | #define bcatStatic(b,s) ((bcatblk)((b), bsStaticBlkParms(s))) 226 | #define bfromStatic(s) ((blk2bstr)(bsStaticBlkParms(s))) 227 | #define bassignStatic(b,s) ((bassignblk)((b), bsStaticBlkParms(s))) 228 | #define binsertStatic(b,p,s,f) ((binsertblk)((b), (p), bsStaticBlkParms(s), (f))) 229 | #define bjoinStatic(b,s) ((bjoinblk)((b), bsStaticBlkParms(s))) 230 | #define biseqStatic(b,s) ((biseqblk)((b), bsStaticBlkParms(s))) 231 | #define bisstemeqStatic(b,s) ((bisstemeqblk)((b), bsStaticBlkParms(s))) 232 | #define biseqcaselessStatic(b,s) ((biseqcaselessblk)((b), bsStaticBlkParms(s))) 233 | #define bisstemeqcaselessStatic(b,s) ((bisstemeqcaselessblk)((b), bsStaticBlkParms(s))) 234 | 235 | /* Reference building macros */ 236 | #define cstr2tbstr btfromcstr 237 | #define btfromcstr(t,s) { \ 238 | (t).data = (unsigned char *) (s); \ 239 | (t).slen = ((t).data) ? ((int) (strlen) ((char *)(t).data)) : 0; \ 240 | (t).mlen = -1; \ 241 | } 242 | #define blk2tbstr(t,s,l) { \ 243 | (t).data = (unsigned char *) (s); \ 244 | (t).slen = l; \ 245 | (t).mlen = -1; \ 246 | } 247 | #define btfromblk(t,s,l) blk2tbstr(t,s,l) 248 | #define bmid2tbstr(t,b,p,l) { \ 249 | const_bstring bstrtmp_s = (b); \ 250 | if (bstrtmp_s && bstrtmp_s->data && bstrtmp_s->slen >= 0) { \ 251 | int bstrtmp_left = (p); \ 252 | int bstrtmp_len = (l); \ 253 | if (bstrtmp_left < 0) { \ 254 | bstrtmp_len += bstrtmp_left; \ 255 | bstrtmp_left = 0; \ 256 | } \ 257 | if (bstrtmp_len > bstrtmp_s->slen - bstrtmp_left) \ 258 | bstrtmp_len = bstrtmp_s->slen - bstrtmp_left; \ 259 | if (bstrtmp_len <= 0) { \ 260 | (t).data = (unsigned char *)""; \ 261 | (t).slen = 0; \ 262 | } else { \ 263 | (t).data = bstrtmp_s->data + bstrtmp_left; \ 264 | (t).slen = bstrtmp_len; \ 265 | } \ 266 | } else { \ 267 | (t).data = (unsigned char *)""; \ 268 | (t).slen = 0; \ 269 | } \ 270 | (t).mlen = -__LINE__; \ 271 | } 272 | #define btfromblkltrimws(t,s,l) { \ 273 | int bstrtmp_idx = 0, bstrtmp_len = (l); \ 274 | unsigned char * bstrtmp_s = (s); \ 275 | if (bstrtmp_s && bstrtmp_len >= 0) { \ 276 | for (; bstrtmp_idx < bstrtmp_len; bstrtmp_idx++) { \ 277 | if (!isspace (bstrtmp_s[bstrtmp_idx])) break; \ 278 | } \ 279 | } \ 280 | (t).data = bstrtmp_s + bstrtmp_idx; \ 281 | (t).slen = bstrtmp_len - bstrtmp_idx; \ 282 | (t).mlen = -__LINE__; \ 283 | } 284 | #define btfromblkrtrimws(t,s,l) { \ 285 | int bstrtmp_len = (l) - 1; \ 286 | unsigned char * bstrtmp_s = (s); \ 287 | if (bstrtmp_s && bstrtmp_len >= 0) { \ 288 | for (; bstrtmp_len >= 0; bstrtmp_len--) { \ 289 | if (!isspace (bstrtmp_s[bstrtmp_len])) break; \ 290 | } \ 291 | } \ 292 | (t).data = bstrtmp_s; \ 293 | (t).slen = bstrtmp_len + 1; \ 294 | (t).mlen = -__LINE__; \ 295 | } 296 | #define btfromblktrimws(t,s,l) { \ 297 | int bstrtmp_idx = 0, bstrtmp_len = (l) - 1; \ 298 | unsigned char * bstrtmp_s = (s); \ 299 | if (bstrtmp_s && bstrtmp_len >= 0) { \ 300 | for (; bstrtmp_idx <= bstrtmp_len; bstrtmp_idx++) { \ 301 | if (!isspace (bstrtmp_s[bstrtmp_idx])) break; \ 302 | } \ 303 | for (; bstrtmp_len >= bstrtmp_idx; bstrtmp_len--) { \ 304 | if (!isspace (bstrtmp_s[bstrtmp_len])) break; \ 305 | } \ 306 | } \ 307 | (t).data = bstrtmp_s + bstrtmp_idx; \ 308 | (t).slen = bstrtmp_len + 1 - bstrtmp_idx; \ 309 | (t).mlen = -__LINE__; \ 310 | } 311 | 312 | /* Write protection macros */ 313 | #define bwriteprotect(t) { if ((t).mlen >= 0) (t).mlen = -1; } 314 | #define bwriteallow(t) { if ((t).mlen == -1) (t).mlen = (t).slen + ((t).slen == 0); } 315 | #define biswriteprotected(t) ((t).mlen <= 0) 316 | 317 | #ifdef __cplusplus 318 | } 319 | #endif 320 | 321 | #endif 322 | 323 | -------------------------------------------------------------------------------- /src/tmesh/include/tmesh/dbg.h: -------------------------------------------------------------------------------- 1 | #ifndef __dbg_h__ 2 | #define __dbg_h__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | /*************************************************** 10 | * MACRO: debug 11 | * ------------------------------------------------- 12 | * Translates any use of 13 | * 14 | * into an fprintf call to the stderr-function. 15 | * 16 | * stderr is a file stream to output all the 17 | * errors. 18 | **************************************************/ 19 | #ifdef NDEBUG 20 | #define debug(M, ...) 21 | #else 22 | #define debug(M, ...) fprintf(stderr, "DEBUG: %s:%d: " M "\n",\ 23 | __FILE__, __LINE__, ##__VA_ARGS__) 24 | #endif 25 | 26 | /*************************************************** 27 | * MACRO: clean_errno 28 | * ------------------------------------------------- 29 | * Used in other macros to get a safe, readable 30 | * version of errno. 31 | * 32 | * strerror-function: 33 | * Returns a pointer to a string that describes the 34 | * error passed in the argument 35 | **************************************************/ 36 | #define clean_errno() (errno == 0 ? "None" : strerror(errno)) 37 | 38 | 39 | /*************************************************** 40 | * MACRO: log_err 41 | * ------------------------------------------------- 42 | * Used to logging error messages to the user 43 | **************************************************/ 44 | #define log_err(M, ...) fprintf(stderr, \ 45 | "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, \ 46 | clean_errno(), ##__VA_ARGS__) 47 | 48 | 49 | /*************************************************** 50 | * MACRO: log_warn 51 | * ------------------------------------------------- 52 | * Used to logging warning messages to the user 53 | **************************************************/ 54 | #define log_warn(M, ...) fprintf(stderr, \ 55 | "[WARN] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, \ 56 | clean_errno(), ##__VA_ARGS__) 57 | 58 | 59 | /*************************************************** 60 | * MACRO: log_info 61 | * ------------------------------------------------- 62 | * Used to logging info messages to the user 63 | **************************************************/ 64 | #define log_info(M, ...) fprintf(stderr, \ 65 | "[INFO] (%s:%d) " M "\n", \ 66 | __FILE__, __LINE__, ##__VA_ARGS__) 67 | 68 | 69 | /*************************************************** 70 | * MACRO: check 71 | * ------------------------------------------------- 72 | * Will make sure, that condition A is true. 73 | * If not, it will log the error M with variable 74 | * arguments for log_err and then jumps to the 75 | * functions error: for cleanup 76 | **************************************************/ 77 | #define check(A, M, ...) if(!(A)) { \ 78 | log_err(M, ##__VA_ARGS__); \ 79 | errno=0; \ 80 | goto error; } 81 | 82 | 83 | /*************************************************** 84 | * MACRO: sentinel 85 | * ------------------------------------------------- 86 | * This macro should be placed in any part of a 87 | * function that shouldn't run and, if it does, 88 | * it prints an error message and then jumps to 89 | * the error: label. 90 | **************************************************/ 91 | #define sentinel(M, ...) { \ 92 | log_err(M, ##__VA_ARGS__); \ 93 | errno=0; \ 94 | goto error; } 95 | 96 | 97 | /*************************************************** 98 | * MACRO: check_mem 99 | * ------------------------------------------------- 100 | * Makes sure that a pointer is valid, and if it 101 | * isn't, it reports it as an error with 102 | * "Out of memory" 103 | **************************************************/ 104 | #define check_mem(A) check((A), "Out of memory.") 105 | 106 | 107 | /*************************************************** 108 | * MACRO: check_debug 109 | * ------------------------------------------------- 110 | * Checks and handles an error, but if the error 111 | * is common, then it doesn't bother reporting it 112 | **************************************************/ 113 | #define check_debug(A, M, ...) if(!(A)) { \ 114 | debug(M, ##__VA_ARGS__); \ 115 | errno=0; \ 116 | goto error; } 117 | 118 | #endif /* __dbg_h__ */ 119 | -------------------------------------------------------------------------------- /src/tmesh/include/tmesh/minunit.h: -------------------------------------------------------------------------------- 1 | #undef NDEBUG 2 | #ifndef _minunit_h 3 | #define _minunit_h 4 | 5 | #include 6 | #include 7 | 8 | #include "tmesh/dbg.h" 9 | 10 | static int tests_run; 11 | 12 | #define mu_suite_start() char *message = NULL 13 | 14 | #define mu_assert(test, message) if (!(test)) {\ 15 | log_err(message); return message; } 16 | 17 | #define mu_run_test(test) debug("\n-----%s", " " #test); \ 18 | message = test(); tests_run++; if (message) return message; 19 | 20 | #define mu_print_tests_run() debug("\nTESTS RUN: %d\n", tests_run) 21 | 22 | #define RUN_TESTS(name) int main(int argc, char *argv[]) {\ 23 | argc = 0;argc++;\ 24 | debug("----- RUNNING: %s", argv[0]);\ 25 | printf("----\nRUNNING: %s\n", argv[0]);\ 26 | char *result = name();\ 27 | if (result != 0) {\ 28 | printf("FAILED: %s\n", result);\ 29 | }\ 30 | else {\ 31 | printf("ALL TESTS PASSED\n");\ 32 | }\ 33 | debug("Tests run: %d\n", tests_run);\ 34 | exit(result != 0);\ 35 | } 36 | 37 | 38 | #endif 39 | 40 | //argc = 1; 41 | -------------------------------------------------------------------------------- /src/tmesh/include/tmesh/tinyexpr.h: -------------------------------------------------------------------------------- 1 | /* 2 | * TINYEXPR - Tiny recursive descent parser and evaluation engine in C 3 | * 4 | * Copyright (c) 2015-2018 Lewis Van Winkle 5 | * 6 | * http://CodePlea.com 7 | * 8 | * This software is provided 'as-is', without any express or implied 9 | * warranty. In no event will the authors be held liable for any damages 10 | * arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, 13 | * including commercial applications, and to alter it and redistribute it 14 | * freely, subject to the following restrictions: 15 | * 16 | * 1. The origin of this software must not be misrepresented; you must not 17 | * claim that you wrote the original software. If you use this software 18 | * in a product, an acknowledgement in the product documentation would be 19 | * appreciated but is not required. 20 | * 2. Altered source versions must be plainly marked as such, and must not be 21 | * misrepresented as being the original software. 22 | * 3. This notice may not be removed or altered from any source distribution. 23 | */ 24 | 25 | #ifndef __TINYEXPR_H__ 26 | #define __TINYEXPR_H__ 27 | 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | 34 | 35 | typedef struct te_expr { 36 | int type; 37 | union {double value; const double *bound; const void *function;}; 38 | void *parameters[1]; 39 | } te_expr; 40 | 41 | 42 | enum { 43 | TE_VARIABLE = 0, 44 | 45 | TE_FUNCTION0 = 8, TE_FUNCTION1, TE_FUNCTION2, TE_FUNCTION3, 46 | TE_FUNCTION4, TE_FUNCTION5, TE_FUNCTION6, TE_FUNCTION7, 47 | 48 | TE_CLOSURE0 = 16, TE_CLOSURE1, TE_CLOSURE2, TE_CLOSURE3, 49 | TE_CLOSURE4, TE_CLOSURE5, TE_CLOSURE6, TE_CLOSURE7, 50 | 51 | TE_FLAG_PURE = 32 52 | }; 53 | 54 | typedef struct te_variable { 55 | const char *name; 56 | const void *address; 57 | int type; 58 | void *context; 59 | } te_variable; 60 | 61 | 62 | 63 | /* Parses the input expression, evaluates it, and frees it. */ 64 | /* Returns NaN on error. */ 65 | double te_interp(const char *expression, int *error); 66 | 67 | /* Parses the input expression and binds variables. */ 68 | /* Returns NULL on error. */ 69 | te_expr *te_compile(const char *expression, const te_variable *variables, int var_count, int *error); 70 | 71 | /* Evaluates the expression. */ 72 | double te_eval(const te_expr *n); 73 | 74 | /* Prints debugging information on the syntax tree. */ 75 | void te_print(const te_expr *n); 76 | 77 | /* Frees the expression. */ 78 | /* This is safe to call on NULL pointers. */ 79 | void te_free(te_expr *n); 80 | 81 | 82 | #ifdef __cplusplus 83 | } 84 | #endif 85 | 86 | #endif /*__TINYEXPR_H__*/ 87 | 88 | -------------------------------------------------------------------------------- /src/tmesh/include/tmesh/tmBdry.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This header file is part of the tmesh library. 3 | * This code was written by Florian Setzwein in 2020, 4 | * and is covered under the MIT License 5 | * Refer to the accompanying documentation for details 6 | * on usage and license. 7 | */ 8 | #ifndef TMESH_TMBDRY_H 9 | #define TMESH_TMBDRY_H 10 | 11 | #include "tmesh/tmTypedefs.h" 12 | 13 | /********************************************************** 14 | * tmBdry: Boundary structure 15 | **********************************************************/ 16 | typedef struct tmBdry { 17 | 18 | /*------------------------------------------------------- 19 | | Parent mesh properties 20 | -------------------------------------------------------*/ 21 | tmMesh *mesh; 22 | 23 | /*------------------------------------------------------- 24 | | Properties of this boundary 25 | -------------------------------------------------------*/ 26 | int no_edges; 27 | int is_interior; 28 | int index; 29 | 30 | tmDouble area; 31 | 32 | /*------------------------------------------------------- 33 | | Boundary edges 34 | -------------------------------------------------------*/ 35 | tmEdge *edges_head; 36 | tmList *edges_stack; 37 | tmQtree *edges_qtree; 38 | tmListNode *mesh_pos; 39 | 40 | } tmBdry; 41 | 42 | 43 | /********************************************************** 44 | * Function: tmBdry_create() 45 | *---------------------------------------------------------- 46 | * Create a new tmBdry structure and returns a pointer 47 | * to it. 48 | *---------------------------------------------------------- 49 | * @return: Pointer to a new tmBdry structure 50 | **********************************************************/ 51 | tmBdry *tmBdry_create(tmMesh *mesh, 52 | tmBool is_interior, 53 | int index); 54 | 55 | /********************************************************** 56 | * Function: tmBdry_destroy() 57 | *---------------------------------------------------------- 58 | * Destroys a tmBdry structure and frees all its 59 | * memory. 60 | *---------------------------------------------------------- 61 | * @param *mesh: pointer to a tmBdry to destroy 62 | * 63 | **********************************************************/ 64 | void tmBdry_destroy(tmBdry *bdry); 65 | 66 | /********************************************************** 67 | * Function: tmBdry_edgeCreate() 68 | *---------------------------------------------------------- 69 | * Function to create a new boundary edge 70 | *---------------------------------------------------------- 71 | * 72 | **********************************************************/ 73 | tmEdge *tmBdry_edgeCreate(tmBdry *bdry, 74 | tmNode *n1, 75 | tmNode *n2, 76 | tmIndex marker, 77 | tmDouble edgeSize); 78 | 79 | /********************************************************** 80 | * Function: tmBdry_addEdge() 81 | *---------------------------------------------------------- 82 | * Function to add an edge to a tmBdry structure 83 | * This edge is the new head of the boundary structure 84 | *---------------------------------------------------------- 85 | * @return: ListNode to tmEdge on the mesh's edge stack 86 | **********************************************************/ 87 | tmListNode *tmBdry_addEdge(tmBdry *bdry, tmEdge *edge); 88 | 89 | /********************************************************** 90 | * Function: tmBdry_remEdge() 91 | *---------------------------------------------------------- 92 | * Function to remove an edge from a tmBdry structure 93 | *---------------------------------------------------------- 94 | * 95 | **********************************************************/ 96 | void tmBdry_remEdge(tmBdry *bdry, tmEdge *edge); 97 | 98 | /********************************************************** 99 | * Function: tmBdry_isLeft() 100 | *---------------------------------------------------------- 101 | * Check if an object is left of all boundary edges 102 | *---------------------------------------------------------- 103 | * @param *edge: pointer to a tmEdge 104 | * @param *obj: pointer to object to check for 105 | * @param obj_type: object type specifier 106 | * @return boolean if object is located on the left of bdry 107 | **********************************************************/ 108 | tmBool tmBdry_isLeft(tmBdry *bdry, void *obj, int obj_type); 109 | 110 | /********************************************************** 111 | * Function: tmBdry_isLeftOn() 112 | *---------------------------------------------------------- 113 | * Check if an object is left of all boundary edges 114 | *---------------------------------------------------------- 115 | * @param *edge: pointer to a tmEdge 116 | * @param *obj: pointer to object to check for 117 | * @param obj_type: object type specifier 118 | * @return boolean if object is located on the left of bdry 119 | **********************************************************/ 120 | tmBool tmBdry_isLeftOn(tmBdry *bdry, void *obj, int obj_type); 121 | 122 | /********************************************************** 123 | * Function: tmBdry_isRight() 124 | *---------------------------------------------------------- 125 | * Check if an object is right of all boundary edges 126 | *---------------------------------------------------------- 127 | * @param *edge: pointer to a tmEdge 128 | * @param *obj: pointer to object to check for 129 | * @param obj_type: object type specifier 130 | * @return boolean if object is located on the left of bdry 131 | **********************************************************/ 132 | tmBool tmBdry_isRight(tmBdry *bdry, void *obj, int obj_type); 133 | 134 | /********************************************************** 135 | * Function: tmBdry_isRightOn() 136 | *---------------------------------------------------------- 137 | * Check if an object is right of all boundary edges 138 | *---------------------------------------------------------- 139 | * @param *edge: pointer to a tmEdge 140 | * @param *obj: pointer to object to check for 141 | * @param obj_type: object type specifier 142 | * @return boolean if object is located on the left of bdry 143 | **********************************************************/ 144 | tmBool tmBdry_isRightOn(tmBdry *bdry, void *obj, int obj_type); 145 | 146 | /********************************************************** 147 | * Function: tmBdry_isInside() 148 | *---------------------------------------------------------- 149 | * Check if an object with position xy is inside of a 150 | * boundary which is enclosed by at least three edges, 151 | * using the Ray-Method. 152 | * If the object is located on the boundary edges, 153 | * it is treated as lying inside. 154 | * 155 | * Check out this source: 156 | * http://alienryderflex.com/polygon/ 157 | *---------------------------------------------------------- 158 | * @param *bdry: pointer to a tmBdry 159 | * @param xy: location to check for 160 | * @return boolean if object is located on the left of bdry 161 | **********************************************************/ 162 | tmBool tmBdry_isInside(tmBdry *bdry, tmDouble xy[2]); 163 | 164 | /********************************************************** 165 | * Function: tmBdry_splitEdge() 166 | *---------------------------------------------------------- 167 | * Split an edge by inserting a new node on its centroid 168 | * and splitting it into two new edges 169 | * This edge will be pointing from its node n1 to the new 170 | * node and a new edge will be created, which points 171 | * from the new node to n2. 172 | *---------------------------------------------------------- 173 | * @param *bdry: pointer to bdry 174 | * @param *edge: pointer to a tmEdge 175 | * @return: pointer to newly created first edge 176 | **********************************************************/ 177 | tmEdge *tmBdry_splitEdge(tmBdry *bdry, tmEdge *edge); 178 | 179 | /********************************************************** 180 | * Function: tmBdry_refine() 181 | *---------------------------------------------------------- 182 | * Refine the edges of a boundary structure according to 183 | * a size function 184 | *---------------------------------------------------------- 185 | * @param *bdry: pointer to bdry 186 | * @return: 187 | **********************************************************/ 188 | void tmBdry_refine(tmBdry *bdry); 189 | 190 | /********************************************************** 191 | * Function: tmBdry_calcArea() 192 | *---------------------------------------------------------- 193 | * Computes the area enclosed by the boundary and sets 194 | * it in the boundaries properties 195 | * 196 | * Reference: 197 | * https://www.wikihow.com/Calculate-the-Area-of-a-Polygon 198 | *---------------------------------------------------------- 199 | * @param *bdry: pointer to bdry 200 | * @return: 201 | **********************************************************/ 202 | void tmBdry_calcArea(tmBdry *bdry); 203 | 204 | /********************************************************** 205 | * Function: tmBdry_initSizeFun() 206 | *---------------------------------------------------------- 207 | * Initializes the size function parameters for all 208 | * boundary nodes, based on respective boundary edge 209 | * lengths and angles. 210 | *---------------------------------------------------------- 211 | * @param *bdry: pointer to bdry 212 | * @return: 213 | **********************************************************/ 214 | void tmBdry_initSizeFun(tmBdry *bdry); 215 | 216 | #endif 217 | -------------------------------------------------------------------------------- /src/tmesh/include/tmesh/tmEdge.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This header file is part of the tmesh library. 3 | * This code was written by Florian Setzwein in 2020, 4 | * and is covered under the MIT License 5 | * Refer to the accompanying documentation for details 6 | * on usage and license. 7 | */ 8 | #ifndef TMESH_TMBDRYEDGE_H 9 | #define TMESH_TMBDRYEDGE_H 10 | 11 | #include "tmesh/tmTypedefs.h" 12 | 13 | /********************************************************** 14 | * tmEdge: Edge structure 15 | **********************************************************/ 16 | typedef struct tmEdge { 17 | 18 | /*------------------------------------------------------- 19 | | Parent structures 20 | -------------------------------------------------------*/ 21 | tmMesh *mesh; 22 | tmBdry *bdry; 23 | tmFront *front; 24 | 25 | /*------------------------------------------------------- 26 | | Edge centroid coordinates 27 | -------------------------------------------------------*/ 28 | tmDouble xy[2]; 29 | tmIndex index; /* Only used for the mesh-output */ 30 | tmIndex bdry_marker; 31 | 32 | /*------------------------------------------------------- 33 | | Properties of this edge 34 | -------------------------------------------------------*/ 35 | tmBool is_on_front; 36 | tmBool is_on_bdry; 37 | tmBool is_on_mesh; 38 | tmBool is_local_delaunay; 39 | 40 | tmListNode *stack_pos; 41 | tmListNode *qtree_pos; 42 | tmQtree *qtree; 43 | 44 | /*------------------------------------------------------- 45 | | Edge length 46 | -------------------------------------------------------*/ 47 | tmDouble len; 48 | 49 | /*------------------------------------------------------- 50 | | Local mesh size factor 51 | -------------------------------------------------------*/ 52 | tmDouble sizeFac; 53 | 54 | /*------------------------------------------------------- 55 | | Vector tangential to edge 56 | -------------------------------------------------------*/ 57 | tmDouble dxy_t[2]; 58 | 59 | /*------------------------------------------------------- 60 | | Vector normal to edge 61 | -------------------------------------------------------*/ 62 | tmDouble dxy_n[2]; 63 | 64 | /*------------------------------------------------------- 65 | | Edge start (n_1) and ending (n_2) nodes 66 | -------------------------------------------------------*/ 67 | tmNode *n1; 68 | tmNode *n2; 69 | 70 | /*------------------------------------------------------- 71 | | Reference of edge in nodes edge lists 72 | -------------------------------------------------------*/ 73 | tmListNode *n1_pos; 74 | tmListNode *n2_pos; 75 | 76 | /*------------------------------------------------------- 77 | | Adjacent triangles to this edge 78 | | t1: left triangle 79 | | t2: right triangle 80 | -------------------------------------------------------*/ 81 | tmTri *t1; 82 | tmTri *t2; 83 | 84 | /*------------------------------------------------------- 85 | | Buffer variables ( e.g. for sorting ) 86 | -------------------------------------------------------*/ 87 | tmDouble dblBuf; 88 | tmIndex indBuf; 89 | 90 | } tmEdge; 91 | 92 | /********************************************************** 93 | * Function: tmEdge_create() 94 | *---------------------------------------------------------- 95 | * Create a new tmEdge structure and return a pointer 96 | * to it. 97 | *---------------------------------------------------------- 98 | * @param mesh: parent mesh of the new edge 99 | * @param n1,n2: Start and ending nodes of this edge 100 | * @param bdry: pointer to boundary the edge belongs to 101 | * @param type: flag for boundary / front / mesh edge 102 | * boundary -> 0 103 | * front -> 1 104 | * mesh -> 2 105 | * @param locSize: local size function value 106 | * 107 | * @return: Pointer to a new tmEdge structure 108 | **********************************************************/ 109 | tmEdge *tmEdge_create(tmMesh *mesh, 110 | tmNode *n1, 111 | tmNode *n2, 112 | tmBdry *bdry, 113 | int edgeType); 114 | 115 | /********************************************************** 116 | * Function: tmEdge_destroy() 117 | *---------------------------------------------------------- 118 | * Destroys a tmEdge structure and frees all its memory. 119 | *---------------------------------------------------------- 120 | * @param *mesh: pointer to a tmEdge to destroy 121 | **********************************************************/ 122 | void tmEdge_destroy(tmEdge *edge); 123 | 124 | /********************************************************** 125 | * Function: tmEdge_isLeft() 126 | *---------------------------------------------------------- 127 | * Check if an object is left of the edge 128 | *---------------------------------------------------------- 129 | * @param *edge: pointer to a tmEdge 130 | * @param *obj: pointer to object to check for 131 | * @param obj_type: object type specifier 132 | * @return boolean if object is located on the left of edge 133 | **********************************************************/ 134 | tmBool tmEdge_isLeft(tmEdge *edge, void *obj, int obj_type); 135 | 136 | /********************************************************** 137 | * Function: tmEdge_isLeftOn() 138 | *---------------------------------------------------------- 139 | * Check if an object is left of or on the edge 140 | *---------------------------------------------------------- 141 | * @param *edge: pointer to a tmEdge 142 | * @param *obj: pointer to object to check for 143 | * @param obj_type: object type specifier 144 | * @return boolean if object is located on the left of edge 145 | **********************************************************/ 146 | tmBool tmEdge_isLeftOn(tmEdge *edge, void *obj, int obj_type); 147 | 148 | /********************************************************** 149 | * Function: tmEdge_isRight() 150 | *---------------------------------------------------------- 151 | * Check if an object is right of the edge 152 | *---------------------------------------------------------- 153 | * @param *edge: pointer to a tmEdge 154 | * @param *obj: pointer to object to check for 155 | * @param obj_type: object type specifier 156 | * @return boolean if object is located on the left of edge 157 | **********************************************************/ 158 | tmBool tmEdge_isRight(tmEdge *edge, void *obj, int obj_type); 159 | 160 | /********************************************************** 161 | * Function: tmEdge_isRightOn() 162 | *---------------------------------------------------------- 163 | * Check if an object is right of or on the edge 164 | *---------------------------------------------------------- 165 | * @param *edge: pointer to a tmEdge 166 | * @param *obj: pointer to object to check for 167 | * @param obj_type: object type specifier 168 | * @return boolean if object is located on the left of edge 169 | **********************************************************/ 170 | tmBool tmEdge_isRightOn(tmEdge *edge, void *obj, int obj_type); 171 | 172 | /********************************************************** 173 | * Function: tmEdge_compareLen() 174 | *---------------------------------------------------------- 175 | * Compare two edges according to their lengths 176 | * 177 | * -> Returns an integer less than zero, if length of e1 is 178 | * less than lenght of e2 179 | * 180 | * -> Returns zero, if length of e1 equals length of e2 181 | * 182 | * -> Returns an integer greater than zero if length of 183 | * e1 is greater than length of e2 184 | *---------------------------------------------------------- 185 | * @param *e1, *e2: pointer to tmEdges to compare 186 | **********************************************************/ 187 | int tmEdge_compareLen(tmEdge *e1, tmEdge *e2); 188 | 189 | /********************************************************** 190 | * Function: tmEdge_createNode() 191 | *---------------------------------------------------------- 192 | * Create new node perpendicular to an edge with a distance 193 | * according to a size function 194 | *---------------------------------------------------------- 195 | * @param edge: pointer to edge 196 | * 197 | **********************************************************/ 198 | tmNode *tmEdge_createNode(tmEdge *edge); 199 | 200 | /********************************************************** 201 | * Function: tmEdge_isLocalDelaunay() 202 | *---------------------------------------------------------- 203 | * Check if an edge is locally delaunay 204 | * If yes, put edge on the non-delaunay edge stack of the 205 | * mesh 206 | *---------------------------------------------------------- 207 | * @param edge: pointer to edge 208 | * 209 | **********************************************************/ 210 | void tmEdge_isDelaunay(tmEdge *edge); 211 | 212 | /********************************************************** 213 | * Function: tmEdge_flipEdge() 214 | *---------------------------------------------------------- 215 | * Perform an edge flip, in order to get a new edge 216 | * which satisfies the delaunay constraint. 217 | * Definition: 218 | * 219 | * n2 220 | * /^^ 221 | * / | \ 222 | * / | \ 223 | * e11 / | \ e22 224 | * / | \ 225 | * / | \ 226 | * / | \ 227 | * p2 v t1 | t2 \ p1 228 | * \ | ^ 229 | * \ |e / 230 | * \ | / 231 | * \ | / 232 | * e12 \ | / e21 233 | * \ | / 234 | * \ | / 235 | * v|/ 236 | * n1 237 | * 238 | * e: (n1, n2) -> Flip to e*: (p1, p2) 239 | * t1: (n1, n2, p2) -> Flip to t1* : (n1, p1, p2) 240 | * t2: (n1, p1, n2) -> Flip to t2* : (n2, p2, p1) 241 | * 242 | * e11: (n2, p2) e12: (p2, n2) 243 | * e21: (n1, p1) e22: (p1, n2) 244 | * 245 | *---------------------------------------------------------- 246 | * @param edge: pointer to edge to flip 247 | * @return : pointer to new edge 248 | * 249 | **********************************************************/ 250 | tmEdge *tmEdge_flipEdge(tmEdge *e); 251 | 252 | #endif 253 | -------------------------------------------------------------------------------- /src/tmesh/include/tmesh/tmFront.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This header file is part of the tmesh library. 3 | * This code was written by Florian Setzwein in 2020, 4 | * and is covered under the MIT License 5 | * Refer to the accompanying documentation for details 6 | * on usage and license. 7 | */ 8 | #ifndef TMESH_TMFRONT_H 9 | #define TMESH_TMFRONT_H 10 | 11 | #include "tmesh/tmTypedefs.h" 12 | 13 | /********************************************************** 14 | * tmBdry: Advancing front structure 15 | **********************************************************/ 16 | typedef struct tmFront { 17 | 18 | /*------------------------------------------------------- 19 | | Parent mesh properties 20 | -------------------------------------------------------*/ 21 | tmMesh *mesh; 22 | 23 | /*------------------------------------------------------- 24 | | Properties of the advancing front 25 | -------------------------------------------------------*/ 26 | int no_edges; 27 | 28 | /*------------------------------------------------------- 29 | | Advancing front edges 30 | -------------------------------------------------------*/ 31 | tmEdge *edges_head; 32 | tmList *edges_stack; 33 | tmQtree *edges_qtree; 34 | 35 | } tmFront; 36 | 37 | 38 | /********************************************************** 39 | * Function: tmFront_create() 40 | *---------------------------------------------------------- 41 | * Create a new tmFront structure and returns a pointer 42 | * to it. 43 | *---------------------------------------------------------- 44 | * @return: Pointer to a new tmFront structure 45 | **********************************************************/ 46 | tmFront *tmFront_create(tmMesh *mesh); 47 | 48 | /********************************************************** 49 | * Function: tmFront_destroy() 50 | *---------------------------------------------------------- 51 | * Destroys a tmFront structure and frees all its 52 | * memory. 53 | *---------------------------------------------------------- 54 | * @param *mesh: pointer to a tmFront to destroy 55 | * 56 | **********************************************************/ 57 | void tmFront_destroy(tmFront *front); 58 | 59 | /********************************************************** 60 | * Function: tmFront_edgeCreate() 61 | *---------------------------------------------------------- 62 | * Function to create a new edge on the advancing front 63 | *---------------------------------------------------------- 64 | * @param front: advancing front structure to add edge to 65 | * @param n1,n2: start / ending node defining the edge 66 | * @param t: triangle that is located to the right 67 | * of the new edge 68 | * 69 | **********************************************************/ 70 | tmEdge *tmFront_edgeCreate(tmFront *front, 71 | tmNode *n1, 72 | tmNode *n2, 73 | tmTri *t); 74 | 75 | /********************************************************** 76 | * Function: tmFront_addEdge() 77 | *---------------------------------------------------------- 78 | * Function to add an edge to a tmFront structure 79 | * This edge is the new head of the front structure 80 | *---------------------------------------------------------- 81 | * @param front: advancing front structure to add edge to 82 | * @param n1,n2: start / ending node defining the edge 83 | * @param t: triangle that is located to the right 84 | * of the new edge 85 | * 86 | **********************************************************/ 87 | tmListNode *tmFront_addEdge(tmFront *front, tmEdge *edge); 88 | 89 | /********************************************************** 90 | * Function: tmFront_remEdge() 91 | *---------------------------------------------------------- 92 | * Function to remove an edge from a tmBdry structure 93 | *---------------------------------------------------------- 94 | * 95 | **********************************************************/ 96 | void tmFront_remEdge(tmFront *front, tmEdge *edge); 97 | 98 | /********************************************************** 99 | * Function: tmFront_init() 100 | *---------------------------------------------------------- 101 | * Function to initialize the advancing front of a mesh 102 | * --> Clone of all current boundaries 103 | *---------------------------------------------------------- 104 | * 105 | **********************************************************/ 106 | void tmFront_init(tmMesh *mesh); 107 | 108 | /********************************************************** 109 | * Function: tmFront_sortEdges() 110 | *---------------------------------------------------------- 111 | * Function to sort the advancing front edges 112 | * according to their length in ascending order 113 | *---------------------------------------------------------- 114 | * 115 | **********************************************************/ 116 | void tmFront_sortEdges(tmMesh *mesh); 117 | 118 | /********************************************************** 119 | * Function: tmFront_advance() 120 | *---------------------------------------------------------- 121 | * Function to advance the front edges 122 | * by one step 123 | *---------------------------------------------------------- 124 | * @parameter mesh: pointer to mesh structure 125 | * @parameter eStart: pointer to advancing front edge 126 | * which will be advanced 127 | * @return boolean: if advancement was successfull 128 | * 129 | **********************************************************/ 130 | tmBool tmFront_advance(tmMesh *mesh, tmEdge *e_ad); 131 | 132 | /********************************************************** 133 | * Function: tmFront_update() 134 | *---------------------------------------------------------- 135 | * Function to update the front edges with a new node 136 | *---------------------------------------------------------- 137 | * @param n: new node which is included in the front 138 | * @param e: current edge which will be replaced 139 | * 140 | **********************************************************/ 141 | void tmFront_update(tmMesh *mesh, 142 | tmNode *n, 143 | tmEdge *e, 144 | tmTri *t); 145 | 146 | /********************************************************** 147 | * Function: tmFront_refine() 148 | *---------------------------------------------------------- 149 | * Refine the edges of the advancing front structure 150 | * according to a size function 151 | *---------------------------------------------------------- 152 | * @param *mesh: pointer to mesh containing the front 153 | * @return: 154 | **********************************************************/ 155 | void tmFront_refine(tmMesh *mesh); 156 | 157 | /********************************************************** 158 | * Function: tmFront_splitEdge() 159 | *---------------------------------------------------------- 160 | * Split an edge by inserting a new node on its centroid 161 | * and splitting it into two new edges 162 | * This edge will be pointing from its node n1 to the new 163 | * node and a new edge will be created, which points 164 | * from the new node to n2. 165 | *---------------------------------------------------------- 166 | * @param *front: pointer to front 167 | * @param *edge: pointer to a tmEdge 168 | * @return: pointer to newly created first edge 169 | **********************************************************/ 170 | tmEdge *tmFront_splitEdge(tmFront *front, tmEdge *edge); 171 | 172 | #endif 173 | -------------------------------------------------------------------------------- /src/tmesh/include/tmesh/tmList.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This header file is part of the tmesh library. 3 | * This code was written by Florian Setzwein in 2020, 4 | * and is covered under the MIT License 5 | * Refer to the accompanying documentation for details 6 | * on usage and license. 7 | * 8 | * Most code in this file has been used from Zed Shaws Book 9 | * "Learn C the hard way" 10 | */ 11 | #ifndef TMESH_TMLIST_H 12 | #define TMESH_TMLIST_H 13 | 14 | 15 | /************************************************************** 16 | * Defines for the handling with list structures 17 | **************************************************************/ 18 | /* Returns the count of a list */ 19 | #define tmList_count(A) ((A)->count) 20 | /* Return the value of the first list entry */ 21 | #define tmList_first(A) ((A)->first != NULL ? (A)->first->value : NULL) 22 | /* Return the value of the last list entry */ 23 | #define tmList_last(A) ((A)->last != NULL ? (A)->last->value : NULL) 24 | /* Return the first list entry */ 25 | #define tmList_first_node(A) ((A)->first != NULL ? (A)->first : NULL) 26 | /* Return the last list entry */ 27 | #define tmList_last_node(A) ((A)->last != NULL ? (A)->last : NULL) 28 | /* Perform a loop over a list structure */ 29 | #define TMLIST_FOREACH(L, S, M, V) tmListNode *_node = NULL;\ 30 | tmListNode *V = NULL;\ 31 | for(V = _node = L->S; _node != NULL; V = _node = _node->M) 32 | 33 | 34 | 35 | /************************************************************** 36 | * ListNode Structure 37 | **************************************************************/ 38 | struct tmListNode; 39 | typedef struct tmListNode { 40 | struct tmListNode *prev; 41 | struct tmListNode *next; 42 | void *value; 43 | } tmListNode; 44 | 45 | /************************************************************** 46 | * List Structure 47 | **************************************************************/ 48 | typedef struct tmList { 49 | int count; 50 | tmListNode *first; 51 | tmListNode *last; 52 | } tmList; 53 | 54 | /************************************************************* 55 | * Function pointer to compare function 56 | *************************************************************/ 57 | typedef int (*tmList_compare) (const void *a, const void *b); 58 | 59 | 60 | 61 | /************************************************************** 62 | * This function creates a new list structure 63 | **************************************************************/ 64 | tmList *tmList_create(); 65 | 66 | /************************************************************** 67 | * This function frees the memory of all ListNodes of a given 68 | * list structure 69 | **************************************************************/ 70 | void tmList_destroy(tmList *list); 71 | 72 | /************************************************************** 73 | * This function frees all memory of the data that is stored 74 | * in a given list structure 75 | **************************************************************/ 76 | void tmList_clear(tmList *list); 77 | 78 | /************************************************************** 79 | * This function frees all memory of a list structure 80 | **************************************************************/ 81 | void tmList_clear_destroy(tmList *list); 82 | 83 | /************************************************************** 84 | * Push a new list node to the end of a list structure 85 | **************************************************************/ 86 | void tmList_push(tmList *list, void *value); 87 | 88 | /************************************************************** 89 | * Remove the last node from a list structure 90 | **************************************************************/ 91 | void *tmList_pop(tmList *list); 92 | 93 | /************************************************************** 94 | * Push a new list node to the beginning of a list structure 95 | **************************************************************/ 96 | void tmList_unshift(tmList *list, void *value); 97 | 98 | /************************************************************** 99 | * Remove the first node from a list structure 100 | **************************************************************/ 101 | void *tmList_shift(tmList *list); 102 | 103 | /************************************************************** 104 | * Remove a specific node from a list structure 105 | **************************************************************/ 106 | void *tmList_remove(tmList *list, tmListNode *node); 107 | 108 | /************************************************************** 109 | * Appends to the end of and frees 110 | * the structure. 111 | **************************************************************/ 112 | void *tmList_join(tmList *list1, tmList *list2); 113 | 114 | /************************************************************* 115 | * Splits a list at a specified Listnode 116 | *************************************************************/ 117 | tmList *tmList_split(tmList *list1, int index); 118 | 119 | 120 | /************************************************************* 121 | * Bubble sort algorithm 122 | *************************************************************/ 123 | int tmList_bubble_sort(tmList *list, tmList_compare cmp); 124 | 125 | /************************************************************* 126 | * Merge sort algorithm 127 | *************************************************************/ 128 | tmList *tmList_merge_sort(tmList *list, tmList_compare cmp); 129 | 130 | #endif /* TMESH_TMLIST_H */ 131 | -------------------------------------------------------------------------------- /src/tmesh/include/tmesh/tmMesh.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This header file is part of the tmesh library. 3 | * This code was written by Florian Setzwein in 2020, 4 | * and is covered under the MIT License 5 | * Refer to the accompanying documentation for details 6 | * on usage and license. 7 | */ 8 | #ifndef TMESH_TMMESH_H 9 | #define TMESH_TMMESH_H 10 | 11 | #include "tmesh/tmTypedefs.h" 12 | 13 | /********************************************************** 14 | * tmMesh: Triangular mesh structure 15 | **********************************************************/ 16 | typedef struct tmMesh { 17 | 18 | /*------------------------------------------------------- 19 | | Mesh properties 20 | -------------------------------------------------------*/ 21 | int qtree_max_obj; 22 | tmDouble xy_min[2]; 23 | tmDouble xy_max[2]; 24 | 25 | tmDouble areaBdry; /* Mesh domain area defined by bdry */ 26 | tmDouble areaTris; /* Mesh domain area defined by tris */ 27 | 28 | tmDouble globSize; /* Global mesh element size */ 29 | 30 | /*------------------------------------------------------- 31 | | Mesh nodes 32 | -------------------------------------------------------*/ 33 | tmNode *nodes_head; 34 | tmList *nodes_stack; 35 | int no_nodes; 36 | tmQtree *nodes_qtree; 37 | 38 | /*------------------------------------------------------- 39 | | Mesh boundaries 40 | -------------------------------------------------------*/ 41 | int no_bdrys; 42 | tmList *bdry_stack; 43 | 44 | /*------------------------------------------------------- 45 | | Mesh advancing front edges 46 | -------------------------------------------------------*/ 47 | tmFront *front; 48 | 49 | /*------------------------------------------------------- 50 | | Mesh size function 51 | -------------------------------------------------------*/ 52 | tmSizeFun sizeFun; 53 | tmSizeFunUser sizeFunUser; 54 | 55 | /*------------------------------------------------------- 56 | | Mesh edges 57 | -------------------------------------------------------*/ 58 | tmList *edges_stack; 59 | int no_edges; 60 | tmQtree *edges_qtree; 61 | 62 | /*------------------------------------------------------- 63 | | Stack to keep track of non-Delaunay edges 64 | -------------------------------------------------------*/ 65 | tmList *delaunay_stack; 66 | 67 | /*------------------------------------------------------- 68 | | Mesh triangles 69 | -------------------------------------------------------*/ 70 | tmTri *tris_head; 71 | tmList *tris_stack; 72 | int no_tris; 73 | tmQtree *tris_qtree; 74 | int no_tris_delaunay; 75 | 76 | } tmMesh; 77 | 78 | 79 | /********************************************************** 80 | * Function: tmMesh_create() 81 | *---------------------------------------------------------- 82 | * Create a new tmMesh structure and returns a pointer 83 | * to it. 84 | *---------------------------------------------------------- 85 | * @return: Pointer to a new tmMesh structure 86 | **********************************************************/ 87 | tmMesh *tmMesh_create(tmDouble xy_min[2], 88 | tmDouble xy_max[2], 89 | int qtree_max_obj, 90 | tmDouble globSize, 91 | tmSizeFunUser sizeFunUser); 92 | 93 | /********************************************************** 94 | * Function: tmMesh_destroy() 95 | *---------------------------------------------------------- 96 | * Destroys a tmMesh structure and frees all its 97 | * memory. 98 | *---------------------------------------------------------- 99 | * @param *mesh: pointer to a tmMesh to destroy 100 | * 101 | **********************************************************/ 102 | void tmMesh_destroy(tmMesh *mesh); 103 | 104 | /********************************************************** 105 | * Function: tmMesh_addNode() 106 | *---------------------------------------------------------- 107 | * Function to add a tmNode to a tmMesh 108 | *---------------------------------------------------------- 109 | * @return: tmNode index on the mesh's node stack 110 | **********************************************************/ 111 | tmListNode *tmMesh_addNode(tmMesh *mesh, tmNode *node); 112 | 113 | /********************************************************** 114 | * Function: tmMesh_edgeCreate() 115 | *---------------------------------------------------------- 116 | * Function to create a new edge for a tmMesh structure 117 | *---------------------------------------------------------- 118 | * @param mesh: mesh for which the edge is defined 119 | * @param n1, n2: start/ending node of edge 120 | * @param t1, t2: triangle to the left / right of the edge 121 | **********************************************************/ 122 | tmEdge *tmMesh_edgeCreate(tmMesh *mesh, 123 | tmNode *n1, tmNode *n2, 124 | tmTri *t1, tmTri *t2, 125 | tmIndex marker); 126 | 127 | /********************************************************** 128 | * Function: tmMesh_addEdge() 129 | *---------------------------------------------------------- 130 | * Function to add an edge to a tmMesh structure 131 | *---------------------------------------------------------- 132 | * @param mesh: mesh for which the edge is defined 133 | * @param edge: edge to add 134 | **********************************************************/ 135 | tmListNode *tmMesh_addEdge(tmMesh *mesh, tmEdge *edge); 136 | 137 | /********************************************************** 138 | * Function: tmMesh_addTri() 139 | *---------------------------------------------------------- 140 | * Function to add a tmTri to a tmMesh 141 | *---------------------------------------------------------- 142 | * @return: tmTri index on the mesh's tri stack 143 | **********************************************************/ 144 | tmListNode *tmMesh_addTri(tmMesh *mesh, tmTri *tri); 145 | 146 | /********************************************************** 147 | * Function: tmMesh_remNode() 148 | *---------------------------------------------------------- 149 | * Function to remove a tmNode from a tmMesh 150 | *---------------------------------------------------------- 151 | * 152 | **********************************************************/ 153 | void tmMesh_remNode(tmMesh *mesh, tmNode *node); 154 | 155 | /********************************************************** 156 | * Function: tmMesh_remEdge() 157 | *---------------------------------------------------------- 158 | * Function to remove an edge from a tmMesh structure 159 | *---------------------------------------------------------- 160 | * 161 | **********************************************************/ 162 | void tmMesh_remEdge(tmMesh *mesh, tmEdge *edge); 163 | 164 | /********************************************************** 165 | * Function: tmMesh_remTri() 166 | *---------------------------------------------------------- 167 | * Function to remove a tmTri from a tmMesh 168 | *---------------------------------------------------------- 169 | * 170 | **********************************************************/ 171 | void tmMesh_remTri(tmMesh *mesh, tmTri *tri); 172 | 173 | /********************************************************** 174 | * Function: tmMesh_addBdry() 175 | *---------------------------------------------------------- 176 | * Function to add a boundary structure to a tmMesh 177 | *---------------------------------------------------------- 178 | * @return: tmBdry pointer 179 | **********************************************************/ 180 | tmBdry *tmMesh_addBdry(tmMesh *mesh, 181 | tmBool is_interior, 182 | int index); 183 | 184 | /********************************************************** 185 | * Function: tmMesh_remBdry() 186 | *---------------------------------------------------------- 187 | * Function to remove a boundary structure from a tmMesh 188 | *---------------------------------------------------------- 189 | * 190 | **********************************************************/ 191 | void tmMesh_remBdry(tmMesh *mesh, tmBdry *bdry); 192 | 193 | /********************************************************** 194 | * Function: tmMesh_objInside() 195 | *---------------------------------------------------------- 196 | * Function to check wether an object at position xy 197 | * is contained within the mesh boundary 198 | *---------------------------------------------------------- 199 | * @param mesh 200 | * @param xy 201 | **********************************************************/ 202 | tmBool tmMesh_objInside(tmMesh *mesh, tmDouble xy[2]); 203 | 204 | /********************************************************** 205 | * Function: tmMesh_printMesh() 206 | *---------------------------------------------------------- 207 | * Fuction to print out the mesh data 208 | *---------------------------------------------------------- 209 | * @param mesh: pointer to mesh structure 210 | **********************************************************/ 211 | void tmMesh_printMesh(tmMesh *mesh); 212 | 213 | /********************************************************** 214 | * Function: tmMesh_printMeshIncomflow() 215 | *---------------------------------------------------------- 216 | * Fuction to print out the mesh data in the format for 217 | * the incomflow solver 218 | *---------------------------------------------------------- 219 | * @param mesh: pointer to mesh structure 220 | **********************************************************/ 221 | void tmMesh_printMeshIncomflow(tmMesh *mesh); 222 | 223 | /********************************************************** 224 | * Function: tmMesh_adfMeshing() 225 | *---------------------------------------------------------- 226 | * Function to perform the advancing front loop 227 | * until either no edges are available anymore or until 228 | * a final iteration is reached 229 | *---------------------------------------------------------- 230 | * 231 | **********************************************************/ 232 | void tmMesh_ADFMeshing(tmMesh *mesh); 233 | 234 | /********************************************************** 235 | * Function: tmMesh_delaunayFlip() 236 | *---------------------------------------------------------- 237 | * Function to perform the flip algorithm on a triangulated 238 | * mesh, in order to obtain a triangulation that is delaunay 239 | *---------------------------------------------------------- 240 | * 241 | **********************************************************/ 242 | void tmMesh_delaunayFlip(tmMesh *mesh); 243 | 244 | /********************************************************** 245 | * Function: tmMesh_setTriNeighbors() 246 | *---------------------------------------------------------- 247 | * Sets for every triangle the connectivity to its neigbors 248 | * This is done, when the advancing front meshing 249 | * has finished. 250 | *---------------------------------------------------------- 251 | * @param mesh: the mesh structure 252 | **********************************************************/ 253 | void tmMesh_setTriNeighbors(tmMesh *mesh); 254 | 255 | /********************************************************** 256 | * Function: tmMesh_calcArea() 257 | *---------------------------------------------------------- 258 | * Function to compute the area enclosed by the entire 259 | * mesh domain 260 | *---------------------------------------------------------- 261 | * @param mesh: mesh for which the edge is defined 262 | **********************************************************/ 263 | void tmMesh_calcArea(tmMesh *mesh); 264 | 265 | /********************************************************** 266 | * Function: tmMesh_getTriFromCoords() 267 | *---------------------------------------------------------- 268 | * Function returns a triangle which contains a given 269 | * point (x,y). If the point is located on the edge 270 | * of two triangles, the first one that has been located 271 | * on the tri-stack will be chosen. 272 | *---------------------------------------------------------- 273 | * @param mesh: mesh for which the edge is defined 274 | * @param xy: point coordinates 275 | * @return: triangle, in which xy is contained. 276 | **********************************************************/ 277 | tmTri* tmMesh_getTriFromCoords(tmMesh *mesh, tmDouble xy[2]); 278 | 279 | /********************************************************** 280 | * Function: tmMesh_refineLocal() 281 | *---------------------------------------------------------- 282 | * Add a new node at a specified location in the mesh 283 | * and subsequently re-triangulate the mesh in this area. 284 | *---------------------------------------------------------- 285 | * @param mesh: the mesh structure 286 | * @param xy: coordinates of the new node to insert 287 | * 288 | **********************************************************/ 289 | void tmMesh_refineLocally(tmMesh *mesh, tmDouble xy[2]); 290 | 291 | /********************************************************** 292 | * Function: tmMesh_sizeFun() 293 | *---------------------------------------------------------- 294 | * Define a global size function for the mesh 295 | *---------------------------------------------------------- 296 | * @param mesh: the mesh structure 297 | * @param xy: coordinates to evaluate the size function 298 | * 299 | **********************************************************/ 300 | tmDouble tmMesh_sizeFun(tmMesh *mesh, tmDouble xy[2]); 301 | 302 | #endif 303 | -------------------------------------------------------------------------------- /src/tmesh/include/tmesh/tmNode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This header file is part of the tmesh library. 3 | * This code was written by Florian Setzwein in 2020, 4 | * and is covered under the MIT License 5 | * Refer to the accompanying documentation for details 6 | * on usage and license. 7 | */ 8 | #ifndef TMESH_TMNODE_H 9 | #define TMESH_TMNODE_H 10 | 11 | #include "tmesh/tmTypedefs.h" 12 | 13 | 14 | /********************************************************** 15 | * tmNode: Node 16 | **********************************************************/ 17 | typedef struct tmNode { 18 | 19 | /*------------------------------------------------------- 20 | | Parent mesh properties 21 | -------------------------------------------------------*/ 22 | tmMesh *mesh; 23 | 24 | /*------------------------------------------------------- 25 | | Node coordinates 26 | -------------------------------------------------------*/ 27 | tmDouble xy[2]; 28 | tmIndex index; /* Only used for the mesh-output */ 29 | tmBool is_active; /* Every node is active by default */ 30 | 31 | /*------------------------------------------------------- 32 | | Properties of this node and its state 33 | -------------------------------------------------------*/ 34 | tmListNode *stack_pos; 35 | tmListNode *qtree_pos; 36 | tmQtree *qtree; 37 | 38 | /*------------------------------------------------------- 39 | | Boundary properties if node is located on a boundary 40 | -------------------------------------------------------*/ 41 | tmBool on_bdry; 42 | tmList *bdry_edges; 43 | int n_bdry_edges; 44 | 45 | /*------------------------------------------------------- 46 | | All adjacent front edges to this node 47 | -------------------------------------------------------*/ 48 | tmBool on_front; 49 | tmList *front_edges; 50 | int n_front_edges; 51 | 52 | /*------------------------------------------------------- 53 | | All mesh edges to this node 54 | -------------------------------------------------------*/ 55 | tmList *mesh_edges; 56 | int n_mesh_edges; 57 | 58 | /*------------------------------------------------------- 59 | | All adjacent triangles to this node 60 | -------------------------------------------------------*/ 61 | tmList *tris; 62 | int n_tris; 63 | 64 | /*------------------------------------------------------- 65 | | Buffer variables ( e.g. for sorting ) 66 | -------------------------------------------------------*/ 67 | tmDouble dblBuf; 68 | tmIndex indBuf; 69 | 70 | /*------------------------------------------------------- 71 | | Size function properties if node is on boundary 72 | -------------------------------------------------------*/ 73 | tmDouble rho; 74 | tmDouble k; 75 | 76 | } tmNode; 77 | 78 | 79 | /********************************************************** 80 | * Function: tmNode_create() 81 | *---------------------------------------------------------- 82 | * Create a new tmNode structure and returns a pointer 83 | * to it. 84 | *---------------------------------------------------------- 85 | * @param mesh: parent mesh of the new node 86 | * @param xy: Node coordinates 87 | * 88 | * @return: Pointer to a new tmNode structure 89 | **********************************************************/ 90 | tmNode *tmNode_create(tmMesh *mesh, tmDouble xy[2]); 91 | 92 | /********************************************************** 93 | * Function: tmNode_destroy() 94 | *---------------------------------------------------------- 95 | * Destroys a tmNode structure and frees all its memory. 96 | *---------------------------------------------------------- 97 | * @param *mesh: pointer to a tmNode to destroy 98 | * 99 | * @return: Returns TRUE if method works 100 | **********************************************************/ 101 | void tmNode_destroy(tmNode *node); 102 | 103 | /********************************************************** 104 | * Function: tmNode_getBdryEdgeIn() 105 | *---------------------------------------------------------- 106 | * Returns a list of ingoing boundary edges 107 | *---------------------------------------------------------- 108 | * @param *mesh: pointer to a tmNode 109 | * 110 | * @return: tmList of tmEdges 111 | **********************************************************/ 112 | tmList *tmNode_getBdryEdgeIn(tmNode *node); 113 | 114 | /********************************************************** 115 | * Function: tmNode_getBdryEdgeOut() 116 | *---------------------------------------------------------- 117 | * Returns a list of outgoing boundary edges 118 | *---------------------------------------------------------- 119 | * @param *mesh: pointer to a tmNode 120 | * 121 | * @return: tmList of tmEdges 122 | **********************************************************/ 123 | tmList *tmNode_getBdryEdgeOut(tmNode *node); 124 | 125 | /********************************************************** 126 | * Function: tmNode_getFrontEdgeIn() 127 | *---------------------------------------------------------- 128 | * Returns a list of ingoing advancing front edges 129 | *---------------------------------------------------------- 130 | * @param *mesh: pointer to a tmNode 131 | * 132 | * @return: tmList of tmEdges 133 | **********************************************************/ 134 | tmList *tmNode_getFrontEdgeIn(tmNode *node); 135 | 136 | /********************************************************** 137 | * Function: tmNode_getFrontEdgeOut() 138 | *---------------------------------------------------------- 139 | * Returns a list of outgoing advancing front edges 140 | *---------------------------------------------------------- 141 | * @param *mesh: pointer to a tmNode 142 | * 143 | * @return: tmList of tmEdges 144 | **********************************************************/ 145 | tmList *tmNode_getFrontEdgeOut(tmNode *node); 146 | 147 | /********************************************************** 148 | * Function: tmNode_getNbrsFromSizeFun 149 | *---------------------------------------------------------- 150 | * Function to estimate neighbouring nodes of a given node 151 | * within a range that is estimated from a sizefunction 152 | *---------------------------------------------------------- 153 | * 154 | **********************************************************/ 155 | tmList *tmNode_getNbrsFromSizeFun(tmNode *node); 156 | 157 | /********************************************************** 158 | * Function: tmNode_getFrontNbrs 159 | *---------------------------------------------------------- 160 | * Returns a list of tmNodes that are connected to a 161 | * given tmNode through advancing front edges 162 | * 163 | *---------------------------------------------------------- 164 | * 165 | **********************************************************/ 166 | tmList *tmNode_getFrontNbrs(tmNode *node); 167 | 168 | /********************************************************** 169 | * Function: tmNode_getAdjFrontEdge() 170 | *---------------------------------------------------------- 171 | * Checks for a node n wether it is connected to a 172 | * node m through an advancing front edge. 173 | * If yes, the edge is returned - otherwise a NULL pointer 174 | * is returned 175 | * 176 | *---------------------------------------------------------- 177 | * @param n: node whose advancing front edges are checked 178 | * @param m: node which is search for on edges other ends 179 | * 180 | **********************************************************/ 181 | tmEdge *tmNode_getAdjFrontEdge(tmNode *n, tmNode *m); 182 | 183 | /********************************************************** 184 | * Function: tmNode_isValid() 185 | *---------------------------------------------------------- 186 | * Checks, if a node is valid for the mesh genereation 187 | * process. The node may not be located too close 188 | * to preceeding edges in its vicinity in order to be valid 189 | * 190 | *---------------------------------------------------------- 191 | * @param node: node to be checked 192 | * 193 | **********************************************************/ 194 | tmBool tmNode_isValid(tmNode *node); 195 | 196 | #endif 197 | -------------------------------------------------------------------------------- /src/tmesh/include/tmesh/tmParam.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This header file is part of the tmesh library. 3 | * This code was written by Florian Setzwein in 2020, 4 | * and is covered under the MIT License 5 | * Refer to the accompanying documentation for details 6 | * on usage and license. 7 | */ 8 | #ifndef TMESH_TMPARAM_H 9 | #define TMESH_TMPARAM_H 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include "tmesh/tmTypedefs.h" 16 | #include "tmesh/bstrlib.h" 17 | 18 | #define FILIO_ERR -1 19 | 20 | /************************************************************* 21 | * Parameter file structure 22 | *************************************************************/ 23 | struct tmParam; 24 | typedef struct tmParam { 25 | const char *path; /* Path of file */ 26 | bstring txt; /* bstring with file data */ 27 | struct bstrList *txtlist; /* file, splitted for newlines */ 28 | 29 | long length; /* Number of chars in total file*/ 30 | /* -> including '\0' at end */ 31 | int nlines; /* Number of lines in total file*/ 32 | 33 | } tmParam; 34 | 35 | /************************************************************* 36 | * Function to create a new parameter file reader structure 37 | *************************************************************/ 38 | tmParam *tmParam_create(const char *file_path); 39 | 40 | /************************************************************* 41 | * Function to destroy a file reader structure 42 | *************************************************************/ 43 | int tmParam_destroy(tmParam *file); 44 | 45 | /************************************************************* 46 | * Function returns a bstring list of lines, that 47 | * do not contain a certain specifier 48 | *************************************************************/ 49 | struct bstrList *tmParam_popLinesWith(struct bstrList *txtlist, 50 | const char *fltr); 51 | 52 | /************************************************************* 53 | * Function returns a bstring list of lines, that 54 | * do contain a certain specifier 55 | *************************************************************/ 56 | struct bstrList *tmParam_getLinesWith(struct bstrList *txtlist, 57 | const char *fltr); 58 | 59 | /************************************************************* 60 | * This function removes all strings in the file that are 61 | * located behind a "comment" identifiert and the next 62 | * new line character 63 | *************************************************************/ 64 | struct bstrList *tmParam_removeComments(struct bstrList *txtlist, 65 | const char *fltr); 66 | 67 | /************************************************************* 68 | * Function searches for a specifier in a bstrList. 69 | * The parameter behind the specifier is then extracted 70 | * from the file and stored into . 71 | * The value is casted to a prescribed type 72 | * type = 0: integer 73 | * type = 1: double 74 | * type = 2: string 75 | * 76 | * Returns 0 if specifier was not found in the file. 77 | * Otherwise, it returns the number of times, the 78 | * specifier was found. 79 | * Returns -1 on errors. 80 | *************************************************************/ 81 | int tmParam_extractParam(struct bstrList *txtlist, 82 | const char *fltr, int type, 83 | void *value); 84 | 85 | /************************************************************* 86 | * Function searches for a specifier in a bstrList. 87 | * The string behind the specifier is then extracted 88 | * from the file and processed as an array of values 89 | * and stored in . 90 | * The values are casted to a prescribed type 91 | * type = 0: integer 92 | * type = 1: double 93 | * type = 2: string 94 | * 95 | * Returns 0 if specifier was not found in the file. 96 | * Otherwise, it returns the number of times, the 97 | * specifier was found. 98 | * Returns -1 on errors. 99 | *************************************************************/ 100 | int tmParam_extractArray(struct bstrList *txtlist, 101 | const char *fltr, int type, 102 | void *value); 103 | 104 | /************************************************************* 105 | * Function to extract the node coordinates from a parameter 106 | * file 107 | *************************************************************/ 108 | int tmParam_readNodeCoords(struct bstrList *txtlist, 109 | tmDouble (**xy)[2], 110 | int *n); 111 | 112 | /************************************************************* 113 | * Function to extract the exterior boundary data 114 | * from a parameter file 115 | * 116 | * @param startStr : start identifier for which to search 117 | * @param endStr : end identifier when to stop searching 118 | * @param startLine: index of line where to start 119 | * @param readAll : boolean if whole file will be read 120 | *************************************************************/ 121 | int tmParam_readBdryData(struct bstrList *txtlist, 122 | char *startStr, 123 | char *endStr, 124 | int startLine, 125 | tmBool readAll, 126 | int (**edges)[2], 127 | int **edgeMarker, 128 | tmDouble **edgeRefine, 129 | int *nEdges, 130 | int *bdryMarker); 131 | 132 | /************************************************************* 133 | * Function to extract the exterior boundary data 134 | * from a parameter file 135 | *************************************************************/ 136 | int tmParam_readExtBdryData(struct bstrList *txtlist, 137 | int (**edges)[2], 138 | int **edgeMarker, 139 | tmDouble **edgeRefine, 140 | int *nEdges, 141 | int *bdryMarkers); 142 | 143 | /************************************************************* 144 | * Function to extract the exterior boundary data 145 | * from a parameter file 146 | *************************************************************/ 147 | int tmParam_readIntBdryData(struct bstrList *txtlist, 148 | int (***edges)[2], 149 | int ***edgeMarker, 150 | tmDouble ***edgeRefine, 151 | int **nEdges, 152 | int **bdryMarkers, 153 | int *nBdrys); 154 | 155 | 156 | #endif 157 | -------------------------------------------------------------------------------- /src/tmesh/include/tmesh/tmQtree.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This header file is part of the tmesh library. 3 | * This code was written by Florian Setzwein in 2020, 4 | * and is covered under the MIT License 5 | * Refer to the accompanying documentation for details 6 | * on usage and license. 7 | */ 8 | #ifndef TMESH_QTREE_H 9 | #define TMESH_QTREE_H 10 | 11 | #include "tmesh/tmTypedefs.h" 12 | 13 | /********************************************************** 14 | * tmQtree: Quadtree structure 15 | **********************************************************/ 16 | typedef struct tmQtree { 17 | 18 | /*------------------------------------------------------- 19 | | Parent mesh properties 20 | -------------------------------------------------------*/ 21 | tmMesh *mesh; 22 | 23 | /*------------------------------------------------------- 24 | | Qtree layer starts at 0 25 | -------------------------------------------------------*/ 26 | tmIndex layer; 27 | tmIndex max_layer; 28 | 29 | /*------------------------------------------------------- 30 | | Maximum number of objects the Qtree can contain 31 | -------------------------------------------------------*/ 32 | int max_obj; 33 | int obj_type; 34 | 35 | /*------------------------------------------------------- 36 | | Bounding box of this Qtree 37 | -------------------------------------------------------*/ 38 | tmDouble xy_min[2]; 39 | tmDouble xy_max[2]; 40 | 41 | /*------------------------------------------------------- 42 | | Centroid of this Qtree 43 | -------------------------------------------------------*/ 44 | tmDouble xy[2]; 45 | 46 | /*------------------------------------------------------- 47 | | Width / height of this Qtree 48 | -------------------------------------------------------*/ 49 | tmDouble dxy[2]; 50 | 51 | /*------------------------------------------------------- 52 | | Objects contained in this Qtree 53 | -------------------------------------------------------*/ 54 | int n_obj_tot; 55 | int n_obj; 56 | tmList *obj; 57 | 58 | /*------------------------------------------------------- 59 | | Parent Qtree and children Qtrees 60 | -------------------------------------------------------*/ 61 | tmQtree *parent; 62 | 63 | tmQtree *child_NE; 64 | tmQtree *child_NW; 65 | tmQtree *child_SW; 66 | tmQtree *child_SE; 67 | 68 | /*------------------------------------------------------- 69 | | Flag if this Qtree is splitted 70 | -------------------------------------------------------*/ 71 | tmBool is_splitted; 72 | 73 | } tmQtree; 74 | 75 | /********************************************************** 76 | * Function: tmQtree_create() 77 | *---------------------------------------------------------- 78 | * Create a new tmQtree structure and return a pointer 79 | * to it. 80 | *---------------------------------------------------------- 81 | * @param mesh: parent mesh of the new Qtree 82 | * @param obj_type: object type of this Qtree 83 | * 84 | * @return: Pointer to a new tmQtree structure 85 | **********************************************************/ 86 | tmQtree *tmQtree_create(tmMesh *mesh, int obj_type); 87 | 88 | /********************************************************** 89 | * Function: tmQtree_destroy() 90 | *---------------------------------------------------------- 91 | * Destroys a tmQtree structure and frees all its memory. 92 | *---------------------------------------------------------- 93 | * @param *mesh: pointer to a tmQtree to destroy 94 | **********************************************************/ 95 | void tmQtree_destroy(tmQtree *qtree); 96 | 97 | /********************************************************** 98 | * Function: tmQtree_init() 99 | *---------------------------------------------------------- 100 | * Initialize a tmQtree structure 101 | *---------------------------------------------------------- 102 | * @param qtree: tmQtree structure to initialize 103 | * 104 | **********************************************************/ 105 | void tmQtree_init(tmQtree *qtree, 106 | tmQtree *parent, tmIndex layer, 107 | tmDouble xy_min[2], tmDouble xy_max[2]); 108 | 109 | /********************************************************** 110 | * Function: tmQtree_addObj() 111 | *---------------------------------------------------------- 112 | * Try to add an object to the qtree 113 | *---------------------------------------------------------- 114 | * @param qtree: tmQtree structure 115 | * @param obj: object to add to the qtree 116 | **********************************************************/ 117 | tmBool tmQtree_addObj(tmQtree *qtree, void *obj); 118 | 119 | /********************************************************** 120 | * Function: tmQtree_remObj() 121 | *---------------------------------------------------------- 122 | * Try to remove an object from the qtree 123 | *---------------------------------------------------------- 124 | * @param qtree: tmQtree structure 125 | * @param obj: object to remove from the qtree 126 | **********************************************************/ 127 | tmBool tmQtree_remObj(tmQtree *qtree, void *obj); 128 | 129 | /********************************************************** 130 | * Function: tmQtree_getObjNo() 131 | *---------------------------------------------------------- 132 | * Return the number of objects contained in this qtree 133 | *---------------------------------------------------------- 134 | * @param qtree: tmQtree structure 135 | **********************************************************/ 136 | int tmQtree_getObjNo(tmQtree *qtree); 137 | 138 | /********************************************************** 139 | * Function: tmQtree_containsObj() 140 | *---------------------------------------------------------- 141 | * Check if a given objects i contained within this qtree 142 | *---------------------------------------------------------- 143 | * @param qtree: tmQtree structure 144 | * @param obj_type: object type of this Qtree 145 | **********************************************************/ 146 | tmBool tmQtree_containsObj(tmQtree *qtree, 147 | void *obj, 148 | int mode); 149 | 150 | /********************************************************** 151 | * Function: tmQtree_getObjBbox() 152 | *---------------------------------------------------------- 153 | * Return a list of objects that are contained within 154 | * a specified bounding box 155 | *---------------------------------------------------------- 156 | * @param qtree: tmQtree structure to initialize 157 | * @param xy_min, xy_max: bounding box 158 | * 159 | **********************************************************/ 160 | tmList *tmQtree_getObjBbox(tmQtree *qtree, 161 | tmDouble xy_min[2], 162 | tmDouble xy_max[2]); 163 | 164 | /********************************************************** 165 | * Function: tmQtree_getObjCirc() 166 | *---------------------------------------------------------- 167 | * Return a list of objects that are contained within 168 | * a specified circle 169 | *---------------------------------------------------------- 170 | * @param qtree: tmQtree structure to initialize 171 | * @param xy: circle centroid 172 | * @param r: circle radius 173 | * 174 | **********************************************************/ 175 | tmList *tmQtree_getObjCirc(tmQtree *qtree, 176 | tmDouble xy[2], 177 | tmDouble r); 178 | 179 | /********************************************************** 180 | * Function: tmQtree_printQtree() 181 | *---------------------------------------------------------- 182 | * Function to print out the qtree data 183 | *---------------------------------------------------------- 184 | * @param qtree: tmQtree structure to initialize 185 | * 186 | **********************************************************/ 187 | void tmQtree_printQtree(tmQtree *qtree); 188 | 189 | #endif 190 | -------------------------------------------------------------------------------- /src/tmesh/include/tmesh/tmTri.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This header file is part of the tmesh library. 3 | * This code was written by Florian Setzwein in 2020, 4 | * and is covered under the MIT License 5 | * Refer to the accompanying documentation for details 6 | * on usage and license. 7 | */ 8 | #ifndef TMESH_TMTRI_H 9 | #define TMESH_TMTRI_H 10 | 11 | #include "tmesh/tmTypedefs.h" 12 | 13 | /********************************************************** 14 | * tmTri: Triangle structure 15 | **********************************************************/ 16 | typedef struct tmTri { 17 | 18 | /*------------------------------------------------------- 19 | | Parent mesh properties 20 | -------------------------------------------------------*/ 21 | tmMesh *mesh; 22 | 23 | /*------------------------------------------------------- 24 | | Triangle index 25 | -------------------------------------------------------*/ 26 | tmListNode *stack_pos; 27 | tmListNode *qtree_pos; 28 | tmQtree *qtree; 29 | 30 | /*------------------------------------------------------- 31 | | Triangle nodes 32 | | Aligned in counter-clockwise orientation 33 | -------------------------------------------------------*/ 34 | tmNode *n1; 35 | tmNode *n2; 36 | tmNode *n3; 37 | 38 | /*------------------------------------------------------- 39 | | Position of this triangle in its nodes triangle-lists 40 | | -> Every node has a list with its adjacent triangles, 41 | | These references recover the position of this 42 | | triangle in the lists of its nodes 43 | -------------------------------------------------------*/ 44 | tmListNode *n1_pos; 45 | tmListNode *n2_pos; 46 | tmListNode *n3_pos; 47 | 48 | /*------------------------------------------------------- 49 | | Triangle neighbors 50 | | Aligned in counter-clockwise orientation 51 | | t1: located opposite of n1 52 | | shares e1 53 | | t2: located opposite of n2 54 | | shares e2 55 | | t3: located pposite of n3 56 | | shares e3 57 | -------------------------------------------------------*/ 58 | tmTri *t1; 59 | tmTri *t2; 60 | tmTri *t3; 61 | 62 | /*------------------------------------------------------- 63 | | Triangle edges ( only edges of the tmMesh_edgeStack ) 64 | | Aligned in counter-clockwise orientation 65 | | e1: located opposite of n1 66 | | adjacent to t1 67 | | e2: located opposite of n2 68 | | adjacent to t2 69 | | e3: located pposite of n3 70 | | adjacent to t3 71 | -------------------------------------------------------*/ 72 | tmEdge *e1; 73 | tmEdge *e2; 74 | tmEdge *e3; 75 | 76 | /*------------------------------------------------------- 77 | | Centroid coordinates 78 | -------------------------------------------------------*/ 79 | tmDouble xy[2]; 80 | tmIndex index; /* Only used for the mesh output */ 81 | 82 | /*------------------------------------------------------- 83 | | Triangle properties 84 | -------------------------------------------------------*/ 85 | tmDouble edgeLen[3]; 86 | tmDouble area; 87 | tmDouble shapeFac; 88 | tmDouble angles[3]; 89 | tmDouble minAngle; 90 | tmDouble maxAngle; 91 | tmDouble quality; 92 | 93 | /*------------------------------------------------------- 94 | | Circumcenter und circumradius 95 | -------------------------------------------------------*/ 96 | tmDouble circ_xy[2]; 97 | tmDouble circ_r; 98 | tmBool is_delaunay; 99 | 100 | /*------------------------------------------------------- 101 | | Buffer variables ( e.g. for sorting ) 102 | -------------------------------------------------------*/ 103 | tmDouble dblBuf; 104 | tmIndex indBuf; 105 | 106 | } tmTri; 107 | 108 | 109 | 110 | /********************************************************** 111 | * Function: tmTri_create() 112 | *---------------------------------------------------------- 113 | * Create a new tmTri structure and return a pointer 114 | * to it. 115 | *---------------------------------------------------------- 116 | * @param mesh: parent mesh of the new triangle 117 | * @param n1,n2,n3: nodes defining the triangle 118 | * 119 | * @return: Pointer to a new tmTri structure 120 | **********************************************************/ 121 | tmTri *tmTri_create(tmMesh *mesh, 122 | tmNode *n1, tmNode *n2, tmNode *n3); 123 | 124 | 125 | /********************************************************** 126 | * Function: tmTri_destroy() 127 | *---------------------------------------------------------- 128 | * Destroys a tmTri structure and frees all its memory. 129 | *---------------------------------------------------------- 130 | * @param *mesh: pointer to a tmTri to destroy 131 | **********************************************************/ 132 | void tmTri_destroy(tmTri *tri); 133 | 134 | /********************************************************** 135 | * Function: tmTri_findNbrTriFromEdge() 136 | *---------------------------------------------------------- 137 | * Searches for a neighboring triangle, which is adjacent 138 | * to an edge defined by two vertices (n1, n2) 139 | * The arrangement of n1 and n2 plays no role. 140 | *---------------------------------------------------------- 141 | * @param n1,n2: nodes defining an edge, for which a 142 | * triangle must be found 143 | * @param tri: triangle for which a neighbor will be found 144 | * if one has been found, it will be included 145 | * to its neighbors 146 | **********************************************************/ 147 | tmTri *tmTri_findTriNeighbor(tmNode *n1, 148 | tmNode *n2, 149 | tmTri *tri); 150 | 151 | /********************************************************** 152 | * Function: tmTri_isValid() 153 | *---------------------------------------------------------- 154 | * Function to check wether a provided triangle is valid 155 | *---------------------------------------------------------- 156 | * @param *tri: pointer to a tmTri 157 | **********************************************************/ 158 | tmBool tmTri_isValid(tmTri *tri); 159 | 160 | /********************************************************** 161 | * Function: tmTri_edgeIntersect() 162 | *---------------------------------------------------------- 163 | * Function to check wether a provided triangles intersects 164 | * with an edge, defined by its vertices e1, e2 165 | *---------------------------------------------------------- 166 | * @param *t1: pointer to first tmTri 167 | * @param *t2: pointer to second tmTri 168 | **********************************************************/ 169 | tmBool tmTri_edgeIntersect(tmTri *t, tmNode *e1, tmNode *e2); 170 | 171 | /********************************************************** 172 | * Function: tmTri_triIntersectn() 173 | *---------------------------------------------------------- 174 | * Function to check wether two provided triangles intersect 175 | *---------------------------------------------------------- 176 | * @param *t1: pointer to first tmTri 177 | * @param *t2: pointer to second tmTri 178 | **********************************************************/ 179 | tmBool tmTri_triIntersect(tmTri *t1, tmTri *t2); 180 | 181 | /********************************************************** 182 | * Function: tmTri_nodeIntersect() 183 | *---------------------------------------------------------- 184 | * Function to check wether a provided triangles intersects 185 | * with a node 186 | *---------------------------------------------------------- 187 | * @param *t: pointer to tmTri 188 | * @param *n: pointer to tmNode 189 | **********************************************************/ 190 | tmBool tmTri_nodeIntersect(tmTri *t, tmNode *n); 191 | 192 | #endif 193 | -------------------------------------------------------------------------------- /src/tmesh/include/tmesh/tmTypedefs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This header file is part of the tmesh library. 3 | * This code was written by Florian Setzwein in 2020, 4 | * and is covered under the MIT License 5 | * Refer to the accompanying documentation for details 6 | * on usage and license. 7 | */ 8 | #ifndef TMESH_TMTYPEDEFS_H 9 | #define TMESH_TMTYPEDEFS_H 10 | 11 | #include 12 | #include 13 | #define _USE_MATH_DEFINES 14 | #include 15 | 16 | #include "tmesh/dbg.h" 17 | #include "tmesh/tmList.h" 18 | 19 | /*********************************************************** 20 | * Flag to use double precision -> undefine to use float 21 | ***********************************************************/ 22 | #define TM_USE_DOUBLE 23 | 24 | /*********************************************************** 25 | * Own type definitions in order to allow to switch from 26 | * switch to short and from double to long in case of 27 | * special memory requirements 28 | ***********************************************************/ 29 | #define tmDouble double 30 | #define tmIndex int 31 | #define tmBool int 32 | #define TRUE 1 33 | #define FALSE 0 34 | 35 | /*********************************************************** 36 | * Basic structure labels 37 | ***********************************************************/ 38 | #define TM_NODE 0 39 | #define TM_EDGE 1 40 | #define TM_TRI 2 41 | 42 | /*********************************************************** 43 | * Basic structure typedefs 44 | ***********************************************************/ 45 | typedef struct tmNode tmNode; 46 | typedef struct tmEdge tmEdge; 47 | typedef struct tmTri tmTri; 48 | typedef struct tmBdry tmBdry; 49 | typedef struct tmFront tmFront; 50 | typedef struct tmQtree tmQtree; 51 | typedef struct tmMesh tmMesh; 52 | 53 | /*********************************************************** 54 | * Function pointers 55 | ***********************************************************/ 56 | typedef tmDouble (*tmSizeFun) (tmMesh *mesh, tmDouble xy[2]); 57 | typedef tmDouble (*tmSizeFunUser) (tmDouble xy[2]); 58 | 59 | 60 | /*********************************************************** 61 | * Debugging Layers 62 | * 0 -> No output 63 | ***********************************************************/ 64 | #define TM_DEBUG 0 65 | 66 | #ifdef TM_DEBUG 67 | #define tmPrint(M, ...) fprintf(stdout, "> " M "\n",\ 68 | ##__VA_ARGS__) 69 | #else 70 | #define tmPrint(M, ...) 71 | #endif 72 | 73 | 74 | /*********************************************************** 75 | * Constants used in code 76 | ***********************************************************/ 77 | #define PI_D 3.1415926535897932384626433832795 78 | #define TM_MIN_SIZE 1.0E-8 79 | #define TM_QTREE_MAX_LAYER 100 80 | 81 | 82 | /*********************************************************** 83 | * MESHING PARAMETERS 84 | ***********************************************************/ 85 | #define TM_NEW_NODE_DIST_FAC ( 1.05 ) // 1.15 86 | #define TM_NODE_EDGE_DIST_FAC ( 0.40 ) 87 | #define TM_TRI_RANGE_FAC ( 2.35 ) 88 | #define TM_BDRY_REFINE_FAC ( 1.00 ) 89 | #define TM_FRONT_REFINE_FAC ( 1.00 ) 90 | #define TM_NODE_NBR_DIST_FAC ( 1.00 ) 91 | #define TM_TRI_NODE_RANGE_FAC ( 1.50 ) 92 | #define TM_TRI_MIN_ANGLE ( ( 15.0*PI_D)/180.0 ) 93 | #define TM_TRI_MAX_ANGLE ( (165.0*PI_D)/180.0 ) 94 | #define TM_TRI_MIN_QUALITY ( 0.04 ) 95 | #define TM_SIZEFUN_SLOPE ( 1.0 ) 96 | 97 | /*********************************************************** 98 | * Minimum and maximum allowed coordinates 99 | ***********************************************************/ 100 | #define TM_X_MIN -1.0E7 101 | #define TM_Y_MIN -1.0E7 102 | #define TM_X_MAX 1.0E7 103 | #define TM_Y_MAX 1.0E7 104 | 105 | #define SMALL 1.0E-13 106 | 107 | /*********************************************************** 108 | * Helper functions 109 | ***********************************************************/ 110 | #ifndef SQR 111 | #define SQR(x) ( (x) * (x) ) 112 | #endif 113 | 114 | #ifndef MAX 115 | #define MAX(a, b) ( (a) > (b) ? (a) : (b) ) 116 | #endif 117 | 118 | #ifndef MIN 119 | #define MIN(a, b) ( (a) < (b) ? (a) : (b) ) 120 | #endif 121 | 122 | #ifndef MAX0 123 | #define MAX0(a) ( (a) > 0 ? (a) : 0 ) 124 | #endif 125 | 126 | #ifndef MIN0 127 | #define MIN0(a) ( (a) < 0 ? (a) : 0 ) 128 | #endif 129 | 130 | #ifndef ABS 131 | #define ABS(a) ( (a) < 0 ? -1 * (a) : (a) ) 132 | #endif 133 | 134 | #ifndef EQ 135 | #define EQ(a, b) ( ABS((a)- (b)) < SMALL ? 1 : 0 ) 136 | #endif 137 | 138 | 139 | /*********************************************************** 140 | * Geometric functions 141 | ***********************************************************/ 142 | #define IN_ON_BBOX(n, min, max) \ 143 | ( ( (n)[0] >= (min)[0] ) \ 144 | && ( (n)[1] >= (min)[1] ) \ 145 | && ( (n)[0] <= (max)[0] ) \ 146 | && ( (n)[1] <= (max)[1] ) ) 147 | 148 | #define IN_BBOX(n, min, max) \ 149 | ( ( (n)[0] > (min)[0] ) \ 150 | && ( (n)[1] > (min)[1] ) \ 151 | && ( (n)[0] < (max)[0] ) \ 152 | && ( (n)[1] < (max)[1] ) ) 153 | 154 | #define ON_BBOX(n, min, max) \ 155 | ( ( EQ( (n)[0], (min)[0] ) && ( (n)[1] >= (min)[1] ) && ( (n)[1] <= (max)[1] ) ) \ 156 | || ( EQ( (n)[0], (max)[0] ) && ( (n)[1] >= (min)[1] ) && ( (n)[1] <= (max)[1] ) ) \ 157 | || ( EQ( (n)[1], (min)[1] ) && ( (n)[0] >= (min)[0] ) && ( (n)[0] <= (max)[0] ) ) \ 158 | || ( EQ( (n)[1], (max)[1] ) && ( (n)[0] >= (min)[0] ) && ( (n)[0] <= (max)[0] ) ) ) 159 | 160 | #define BBOX_OVERLAP(pqmin, pqmax, rsmin, rsmax) \ 161 | ( ( (pqmin)[0] <= (rsmax)[0] ) \ 162 | && ( (rsmin)[0] <= (pqmax)[0] ) \ 163 | && ( (pqmin)[1] <= (rsmax)[1] ) \ 164 | && ( (rsmin)[1] <= (pqmax)[1] ) ) 165 | 166 | 167 | /*---------------------------------------------------------- 168 | | check the orientation of a node tuple (p,q,r) 169 | ----------------------------------------------------------*/ 170 | static inline int ORIENTATION(tmDouble p[2], 171 | tmDouble q[2], 172 | tmDouble r[2]) 173 | { 174 | tmDouble area2 = ( ( p[0] - r[0] ) * ( q[1] - r[1] ) 175 | - ( q[0] - r[0] ) * ( p[1] - r[1] ) ); 176 | 177 | /* Colinearity of all nodes */ 178 | if ( (area2 * area2) < SMALL ) 179 | return 0; 180 | 181 | /* Counter clockwise orienation */ 182 | if ( area2 > 0.0 ) 183 | return 1; 184 | 185 | return 2; 186 | } 187 | 188 | /*---------------------------------------------------------- 189 | | check if node r is located to the left of (p,q) 190 | ----------------------------------------------------------*/ 191 | static inline tmBool IS_LEFT(tmDouble p[2], 192 | tmDouble q[2], 193 | tmDouble r[2]) 194 | { 195 | if ( ORIENTATION(p, q, r) == 1 ) 196 | return TRUE; 197 | return FALSE; 198 | } 199 | 200 | /*---------------------------------------------------------- 201 | | check if node r is located to the left of (p,q) or on it 202 | ----------------------------------------------------------*/ 203 | static inline tmBool IS_LEFTON(tmDouble p[2], 204 | tmDouble q[2], 205 | tmDouble r[2]) 206 | { 207 | if ( ORIENTATION(p, q, r) == 2 ) 208 | return FALSE; 209 | return TRUE; 210 | } 211 | 212 | /*---------------------------------------------------------- 213 | | check if node r is located to the right of (p,q) 214 | ----------------------------------------------------------*/ 215 | static inline tmBool IS_RIGHT(tmDouble p[2], 216 | tmDouble q[2], 217 | tmDouble r[2]) 218 | { 219 | if ( ORIENTATION(p, q, r) == 2 ) 220 | return TRUE; 221 | return FALSE; 222 | } 223 | 224 | /*---------------------------------------------------------- 225 | | check if node r is located to the right of (p,q) or on it 226 | ----------------------------------------------------------*/ 227 | static inline tmBool IS_RIGHTON(tmDouble p[2], 228 | tmDouble q[2], 229 | tmDouble r[2]) 230 | { 231 | if ( ORIENTATION(p, q, r) == 1 ) 232 | return FALSE; 233 | return TRUE; 234 | } 235 | 236 | /*---------------------------------------------------------- 237 | | Function returns the squared normal distance between an 238 | | edge and a node. 239 | | The edge is defined through its vertices (v,w) 240 | | The node is defined through its coordinates p 241 | | 242 | | Source: 243 | | https://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment 244 | ----------------------------------------------------------*/ 245 | static inline tmDouble EDGE_NODE_DIST2(tmDouble v[2], 246 | tmDouble w[2], 247 | tmDouble p[2]) 248 | { 249 | const tmDouble dx_e = w[0]-v[0]; 250 | const tmDouble dy_e = w[1]-v[1]; 251 | const tmDouble l2 = dx_e*dx_e + dy_e*dy_e; 252 | 253 | const tmDouble dotP = ( (p[0]-v[0]) * dx_e 254 | + (p[1]-v[1]) * dy_e ) / l2; 255 | 256 | const tmDouble t = MAX(0.0, MIN(1.0, dotP)); 257 | 258 | const tmDouble proj_x = v[0] + t * dx_e; 259 | const tmDouble proj_y = v[1] + t * dy_e; 260 | 261 | const tmDouble dx = proj_x - p[0]; 262 | const tmDouble dy = proj_y - p[1]; 263 | 264 | const tmDouble dist2 = dx*dx + dy*dy; 265 | 266 | return dist2; 267 | } 268 | 269 | /*---------------------------------------------------------- 270 | | Check if an object is contained in a provided list 271 | ----------------------------------------------------------*/ 272 | static inline tmBool OBJ_IN_LIST(void *obj, tmList *list) 273 | { 274 | tmListNode *cur; 275 | for (cur = list->first; cur != NULL; cur = cur->next) 276 | if ( cur->value == obj ) 277 | return TRUE; 278 | 279 | return FALSE; 280 | error: 281 | return -1; 282 | } 283 | 284 | /*---------------------------------------------------------- 285 | | Check if r lies within a segment (p,q) 286 | ----------------------------------------------------------*/ 287 | static inline tmBool IN_SEGMENT(tmDouble p[2], 288 | tmDouble q[2], 289 | tmDouble r[2]) 290 | { 291 | if ( ORIENTATION(p, q, r) != 0 ) 292 | return FALSE; 293 | 294 | tmDouble bbox_min[2] = { MIN(p[0], q[0]), 295 | MIN(p[1], q[1]) }; 296 | tmDouble bbox_max[2] = { MAX(p[0], q[0]), 297 | MAX(p[1], q[1]) }; 298 | 299 | const tmDouble dx_e = q[0]-p[0]; 300 | const tmDouble dy_e = q[1]-p[1]; 301 | const tmDouble l2 = dx_e*dx_e + dy_e*dy_e; 302 | const tmDouble t = ( (r[0]-p[0]) * dx_e 303 | + (r[1]-p[1]) * dy_e ) / l2; 304 | 305 | if ( t > 0.0 && t < 1.0 ) 306 | return TRUE; 307 | 308 | return FALSE; 309 | } 310 | 311 | /*---------------------------------------------------------- 312 | | Check if r lies within a segment (p,q) or on its endpoints 313 | ----------------------------------------------------------*/ 314 | static inline tmBool IN_ON_SEGMENT(tmDouble p[2], 315 | tmDouble q[2], 316 | tmDouble r[2]) 317 | { 318 | if ( ORIENTATION(p, q, r) != 0 ) 319 | return FALSE; 320 | 321 | tmDouble bbox_min[2] = { MIN(p[0], q[0]), 322 | MIN(p[1], q[1]) }; 323 | tmDouble bbox_max[2] = { MAX(p[0], q[0]), 324 | MAX(p[1], q[1]) }; 325 | 326 | const tmDouble dx_e = q[0]-p[0]; 327 | const tmDouble dy_e = q[1]-p[1]; 328 | const tmDouble l2 = dx_e*dx_e + dy_e*dy_e; 329 | const tmDouble t = ( (r[0]-p[0]) * dx_e 330 | + (r[1]-p[1]) * dy_e ) / l2; 331 | 332 | if ( t >= 0.0 && t <= 1.0 ) 333 | return TRUE; 334 | 335 | return FALSE; 336 | } 337 | 338 | /*---------------------------------------------------------- 339 | | Check if two line segments (p1,q1), (p2,q2) are crossing 340 | | 341 | | * Returns True, if segments intersect at any point but 342 | | their endings 343 | | * Returns True, if one line contains a part of the other 344 | | * Returns False, if both lines share both end points 345 | | * Returns False in all other cases 346 | | 347 | | -> Used for triangle edge intersection 348 | ----------------------------------------------------------*/ 349 | static inline tmBool INTERSECTION_IN_LINES(tmDouble p1[2], 350 | tmDouble q1[2], 351 | tmDouble p2[2], 352 | tmDouble q2[2]) 353 | { 354 | int o1 = ORIENTATION(p1, q1, p2); 355 | int o2 = ORIENTATION(p1, q1, q2); 356 | int o3 = ORIENTATION(p2, q2, p1); 357 | int o4 = ORIENTATION(p2, q2, q1); 358 | 359 | if ( ( (o1 == 1 && o2 == 2) || (o1 == 2 && o2 == 1) ) 360 | && ( (o3 == 1 && o4 == 2) || (o3 == 2 && o4 == 1) ) ) 361 | { 362 | return TRUE; 363 | } 364 | 365 | /* (p1, q1) and p2 are colinear and p2 lies on segment (p1, q1) */ 366 | if ( (o1 == 0) && ( IN_SEGMENT(p1, q1, p2) == TRUE ) ) 367 | return TRUE; 368 | 369 | /* (p1, q1) and q2 are colinear and q2 lies on segment (p1, q1) */ 370 | if ( (o2 == 0) && ( IN_SEGMENT(p1, q1, q2) == TRUE ) ) 371 | return TRUE; 372 | 373 | /* (p2, q2) and p1 are colinear and p1 lies on segment (p2, q2) */ 374 | if ( (o3 == 0) && ( IN_SEGMENT(p2, q2, p1) == TRUE ) ) 375 | return TRUE; 376 | 377 | /* (p2, q2) and q1 are colinear and q1 lies on segment (p2, q2) */ 378 | if ( (o4 == 0) && ( IN_SEGMENT(p2, q2, q1) == TRUE )) 379 | return TRUE; 380 | 381 | return FALSE; 382 | 383 | } 384 | 385 | 386 | #endif /* TMESH_TMTYPEDEFS_H */ 387 | -------------------------------------------------------------------------------- /src/tmesh/src/main.c: -------------------------------------------------------------------------------- 1 | #include "tmesh/tmParam.h" 2 | #include "tmesh/tmNode.h" 3 | #include "tmesh/tmEdge.h" 4 | #include "tmesh/tmTri.h" 5 | #include "tmesh/tmBdry.h" 6 | #include "tmesh/tmMesh.h" 7 | #include "tmesh/tmQtree.h" 8 | #include "tmesh/tmFront.h" 9 | #include "tmesh/tmList.h" 10 | 11 | #include "tmesh/tinyexpr.h" 12 | 13 | #include 14 | #include 15 | #define _USE_MATH_DEFINES 16 | #include 17 | #include 18 | 19 | 20 | tmDouble x, y; 21 | te_variable vars[] = {{"x", &x}, {"y", &y}}; 22 | te_expr *expr; 23 | 24 | static inline tmDouble sizeFun( tmDouble xy[2] ) 25 | { 26 | x = xy[0]; 27 | y = xy[1]; 28 | return te_eval(expr); 29 | } 30 | 31 | 32 | /************************************************************* 33 | * 34 | *************************************************************/ 35 | int main(int argc, char *argv[]) 36 | { 37 | if (argc < 2) 38 | { 39 | tmPrint("tmesh "); 40 | return 0; 41 | } 42 | 43 | char *input = argv[1]; 44 | tmParam *file; 45 | 46 | int i,j; 47 | 48 | tmSizeFunUser sizeFunUser; 49 | 50 | tmDouble globSize; 51 | tmDouble *globBbox = NULL; 52 | int qtreeSize; 53 | bstring sizeFunExpr; 54 | 55 | tmDouble (*nodes)[2] = NULL; 56 | int nNodes; 57 | 58 | int (*extBdryEdges)[2] = NULL; 59 | int *extBdryEdgeMarker = NULL; 60 | tmDouble *extBdryRefinement = NULL; 61 | int nExtBdryEdges; 62 | int extBdryMarker; 63 | 64 | int (**intrEdges)[2] = NULL; 65 | int **intrEdgeMarkers = NULL; 66 | tmDouble **intrEdgeRefinements = NULL; 67 | int *nIntrEdges = NULL; 68 | int *intrBdryMarkers = NULL; 69 | int nIntrBdrys = 0; 70 | 71 | 72 | /*---------------------------------------------------------- 73 | | Load parameter file and clear comments 74 | ----------------------------------------------------------*/ 75 | struct bstrList *buf; 76 | 77 | file = tmParam_create( input ); 78 | buf = tmParam_removeComments(file->txtlist, "#"); 79 | bstrListDestroy(file->txtlist); 80 | file->txtlist = buf; 81 | 82 | /*---------------------------------------------------------- 83 | | Extract mandatory meshing parameters 84 | ----------------------------------------------------------*/ 85 | check( tmParam_extractParam(file->txtlist, 86 | "Global element size:", 1, &globSize) != 0, 87 | "Missing parameter "); 88 | 89 | check( tmParam_extractArray(file->txtlist, 90 | "Mesh bounding box:", 1, &globBbox) != 0, 91 | "Missing parameter "); 92 | 93 | /*---------------------------------------------------------- 94 | | Extract optional meshing parameters 95 | ----------------------------------------------------------*/ 96 | if ( tmParam_extractParam(file->txtlist, 97 | "Number of quadtree elements:", 0, &qtreeSize) == 0 ) 98 | { 99 | qtreeSize = 100; 100 | } 101 | 102 | if ( tmParam_extractParam(file->txtlist, 103 | "Size function:", 2, &sizeFunExpr) != 0 ) 104 | { 105 | int err; 106 | expr = te_compile(sizeFunExpr->data, vars, 2, &err); 107 | check(err == 0, "Wrong size function definition"); 108 | tmPrint("SIZE FUNCTION: %s", sizeFunExpr->data); 109 | sizeFunUser = sizeFun; 110 | } 111 | else { 112 | sizeFunExpr = NULL; 113 | sizeFunUser = NULL; 114 | } 115 | 116 | /*---------------------------------------------------------- 117 | | Extract node definitions 118 | ----------------------------------------------------------*/ 119 | tmParam_readNodeCoords(file->txtlist, &nodes, &nNodes); 120 | 121 | /*---------------------------------------------------------- 122 | | Extract exterior boundary definition 123 | ----------------------------------------------------------*/ 124 | tmParam_readExtBdryData(file->txtlist, 125 | &extBdryEdges, 126 | &extBdryEdgeMarker, 127 | &extBdryRefinement, 128 | &nExtBdryEdges, 129 | &extBdryMarker); 130 | 131 | /*---------------------------------------------------------- 132 | | Extract interior boundary definitions 133 | ----------------------------------------------------------*/ 134 | tmParam_readIntBdryData(file->txtlist, 135 | &intrEdges, 136 | &intrEdgeMarkers, 137 | &intrEdgeRefinements, 138 | &nIntrEdges, 139 | &intrBdryMarkers, 140 | &nIntrBdrys); 141 | 142 | /*---------------------------------------------------------- 143 | | Build the mesh 144 | ----------------------------------------------------------*/ 145 | tmDouble xyMin[2] = { globBbox[0], globBbox[1] }; 146 | tmDouble xyMax[2] = { globBbox[2], globBbox[3] }; 147 | 148 | tmMesh *mesh = tmMesh_create(xyMin, xyMax, 149 | qtreeSize, 150 | globSize, 151 | sizeFunUser); 152 | 153 | 154 | /*---------------------------------------------------------- 155 | | Add nodes to the mesh 156 | ----------------------------------------------------------*/ 157 | tmNode **nodes_ptr = calloc(nNodes, sizeof(tmNode*)); 158 | tmNode *newNode; 159 | 160 | for (i = 0; i < nNodes; i++) 161 | { 162 | newNode = tmNode_create(mesh, nodes[i]); 163 | nodes_ptr[i] = newNode; 164 | } 165 | 166 | /*---------------------------------------------------------- 167 | | Add exterior boundary to the mesh 168 | ----------------------------------------------------------*/ 169 | tmEdge *bdryEdge; 170 | tmBdry *bdry_ext = tmMesh_addBdry(mesh, 171 | FALSE, 172 | extBdryMarker); 173 | 174 | for (i = 0; i < nExtBdryEdges; i++) 175 | { 176 | int i0 = extBdryEdges[i][0]; 177 | int i1 = extBdryEdges[i][1]; 178 | 179 | check( i0 < nNodes && i1 < nNodes, 180 | "Defined nodes do not fit to exterior boundary definition."); 181 | 182 | bdryEdge = tmBdry_edgeCreate(bdry_ext, 183 | nodes_ptr[i0], 184 | nodes_ptr[i1], 185 | extBdryEdgeMarker[i], 186 | extBdryRefinement[i]); 187 | } 188 | 189 | 190 | /*---------------------------------------------------------- 191 | | Add interior boundaries to the mesh 192 | ----------------------------------------------------------*/ 193 | tmBdry *bdry_int; 194 | for (j = 0; j < nIntrBdrys; j++) 195 | { 196 | bdry_int = tmMesh_addBdry(mesh, 197 | TRUE, 198 | intrBdryMarkers[j]); 199 | 200 | for (i = 0; i < nIntrEdges[j]; i++) 201 | { 202 | int i0 = intrEdges[j][i][0]; 203 | int i1 = intrEdges[j][i][1]; 204 | 205 | check( i0 < nNodes && i1 < nNodes, 206 | "Defined nodes do not fit to interior boundary with marker %d.", 207 | intrBdryMarkers[j]); 208 | 209 | bdryEdge = tmBdry_edgeCreate(bdry_int, 210 | nodes_ptr[i0], 211 | nodes_ptr[i1], 212 | intrEdgeMarkers[j][i], 213 | intrEdgeRefinements[j][i]); 214 | } 215 | } 216 | 217 | /*-------------------------------------------------------- 218 | | Create mesh 219 | --------------------------------------------------------*/ 220 | clock_t tic_1 = clock(); 221 | tmMesh_ADFMeshing(mesh); 222 | clock_t tic_2 = clock(); 223 | 224 | /*-------------------------------------------------------- 225 | | Print the mesh data 226 | --------------------------------------------------------*/ 227 | //tmMesh_printMesh(mesh); 228 | tmMesh_printMeshIncomflow(mesh); 229 | 230 | 231 | tmPrint("----------------------------------------------\n"); 232 | tmPrint("TMesh finished\n"); 233 | tmPrint("----------------------------------------------\n"); 234 | tmPrint("Number of elements: %d\n", mesh->no_tris); 235 | tmPrint("Meshing time : %e sec\n", 236 | (double) (tic_2 - tic_1) / CLOCKS_PER_SEC ); 237 | tmPrint("----------------------------------------------\n"); 238 | 239 | tmMesh_destroy(mesh); 240 | 241 | 242 | 243 | te_free(expr); 244 | free(globBbox); 245 | bdestroy(sizeFunExpr); 246 | 247 | free(nodes); 248 | free(nodes_ptr); 249 | 250 | free(extBdryEdges); 251 | free(extBdryEdgeMarker); 252 | free(extBdryRefinement); 253 | 254 | for (i = 0; i < nIntrBdrys; i++) 255 | { 256 | free(intrEdges[i]); 257 | free(intrEdgeMarkers[i]); 258 | free(intrEdgeRefinements[i]); 259 | } 260 | free(intrEdges); 261 | free(intrEdgeMarkers); 262 | free(intrEdgeRefinements); 263 | free(nIntrEdges); 264 | free(intrBdryMarkers); 265 | 266 | tmParam_destroy( file ); 267 | 268 | return 0; 269 | 270 | 271 | 272 | error: 273 | 274 | te_free(expr); 275 | free(globBbox); 276 | bdestroy(sizeFunExpr); 277 | 278 | free(nodes); 279 | 280 | free(extBdryEdges); 281 | free(extBdryEdgeMarker); 282 | free(extBdryRefinement); 283 | 284 | for (i = 0; i < nIntrBdrys; i++) 285 | { 286 | free(intrEdges[i]); 287 | free(intrEdgeMarkers[i]); 288 | free(intrEdgeRefinements[i]); 289 | } 290 | free(intrEdges); 291 | free(intrEdgeMarkers); 292 | free(intrEdgeRefinements); 293 | free(nIntrEdges); 294 | free(intrBdryMarkers); 295 | 296 | tmParam_destroy( file ); 297 | 298 | return 1; 299 | 300 | } 301 | -------------------------------------------------------------------------------- /src/tmesh/src/tmList.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This source file is part of the tmesh library. 3 | * This code was written by Florian Setzwein in 2020, 4 | * and is covered under the MIT License 5 | * Refer to the accompanying documentation for details 6 | * on usage and license. 7 | * 8 | * Most code in this file has been used from Zed Shaws Book 9 | * "Learn C the hard way" 10 | */ 11 | #include 12 | #include "tmesh/tmList.h" 13 | #include "tmesh/dbg.h" 14 | 15 | 16 | /************************************************************** 17 | * This function creates a new list structure 18 | **************************************************************/ 19 | tmList *tmList_create() 20 | { 21 | return calloc(1, sizeof(tmList)); 22 | } 23 | 24 | /************************************************************** 25 | * This function frees the memory of all tmListNodes of a given 26 | * list structure 27 | **************************************************************/ 28 | void tmList_destroy(tmList *list) 29 | { 30 | TMLIST_FOREACH(list, first, next, cur) { 31 | if (cur->prev) { 32 | free(cur->prev); 33 | } 34 | } 35 | free(list->last); 36 | free(list); 37 | } 38 | 39 | /************************************************************** 40 | * This function frees all memory of the data that is stored 41 | * in a given list structure 42 | **************************************************************/ 43 | void tmList_clear(tmList *list) 44 | { 45 | TMLIST_FOREACH(list, first, next, cur) { 46 | free(cur->value); 47 | } 48 | } 49 | 50 | /************************************************************** 51 | * This function frees all memory of a list structure 52 | **************************************************************/ 53 | void tmList_clear_destroy(tmList *list) 54 | { 55 | tmList_clear(list); 56 | tmList_destroy(list); 57 | } 58 | 59 | /************************************************************** 60 | * Push a new list node to the end of a list structure 61 | **************************************************************/ 62 | void tmList_push(tmList *list, void *value) 63 | { 64 | tmListNode *node = calloc(1, sizeof(tmListNode)); 65 | check_mem(node); 66 | 67 | node->value = value; 68 | 69 | if (list->last == NULL) { 70 | list->first = node; 71 | list->last = node; 72 | } 73 | else { 74 | list->last->next = node; 75 | node->prev = list->last; 76 | list->last = node; 77 | } 78 | 79 | list->count++; 80 | 81 | error: 82 | return; 83 | } 84 | 85 | /************************************************************** 86 | * Remove the last node from a list structure 87 | **************************************************************/ 88 | void *tmList_pop(tmList *list) 89 | { 90 | tmListNode *node = list->last; 91 | return node != NULL ? tmList_remove(list, node) : NULL; 92 | } 93 | 94 | /************************************************************** 95 | * Push a new list node to the beginning of a list structure 96 | **************************************************************/ 97 | void tmList_unshift(tmList *list, void *value) 98 | { 99 | tmListNode *node = calloc(1, sizeof(tmListNode)); 100 | check_mem(node); 101 | 102 | node->value = value; 103 | 104 | if (list->first == NULL) { 105 | list->first = node; 106 | list->last = node; 107 | } 108 | else { 109 | node->next = list->first; 110 | list->first->prev = node; 111 | list->first = node; 112 | } 113 | 114 | list->count++; 115 | 116 | error: 117 | return; 118 | } 119 | 120 | /************************************************************** 121 | * Remove the first node from a list structure 122 | **************************************************************/ 123 | void *tmList_shift(tmList *list) 124 | { 125 | tmListNode *node = list->first; 126 | return node != NULL ? tmList_remove(list, node) : NULL; 127 | } 128 | 129 | /************************************************************** 130 | * Remove a specific node from a list structure 131 | **************************************************************/ 132 | void *tmList_remove(tmList *list, tmListNode *node) 133 | { 134 | void *result = NULL; 135 | 136 | check(list->first && list->last, "tmList is empty."); 137 | check(node, "node can't be NULL."); 138 | 139 | if (node == list->first && node == list->last) { 140 | list->first = NULL; 141 | list->last = NULL; 142 | } 143 | else if (node == list->first) { 144 | list->first = node->next; 145 | check(list->first != NULL, "Invalid list, somehow got a first that is NULL."); 146 | list->first->prev = NULL; 147 | } 148 | else if (node == list->last) { 149 | list->last = node->prev; 150 | check(list->last != NULL, "Invalid list, somehow got a last that is NULL."); 151 | list->last->next = NULL; 152 | } 153 | else { 154 | tmListNode *after = node->next; 155 | tmListNode *before = node->prev; 156 | 157 | after->prev = before; 158 | before->next = after; 159 | } 160 | 161 | list->count--; 162 | result = node->value; 163 | free(node); 164 | 165 | error: 166 | return result; 167 | } 168 | 169 | /************************************************************** 170 | * Appends to the end of 171 | **************************************************************/ 172 | void *tmList_join(tmList *list1, tmList *list2) 173 | { 174 | check(list1->first || list2->first, "Both lists are empty."); 175 | 176 | if (list1->first == NULL) { 177 | list1->first = list2->first; 178 | list1->last = list2->last; 179 | list1->count = list2->count; 180 | 181 | } 182 | else { 183 | list1->last->next = list2->first; 184 | list2->first->prev = list1->last; 185 | list1->last = list2->last; 186 | list1->count += list2->count; 187 | 188 | } 189 | 190 | list2->count = 0; 191 | list2->first = NULL; 192 | list2->last = NULL; 193 | 194 | tmList_destroy(list2); 195 | 196 | error: 197 | return NULL; 198 | } 199 | 200 | 201 | /************************************************************* 202 | * Splits a list at a specified index of the list 203 | *************************************************************/ 204 | tmList *tmList_split(tmList *list1, int index) 205 | { 206 | if (index == 0) 207 | return list1; 208 | 209 | if (list1->count <= 1) 210 | return list1; 211 | 212 | if (index >= list1->count || index < 0) 213 | return list1; 214 | 215 | tmListNode *node = list1->first; 216 | 217 | int i = 0; 218 | while (i < index) 219 | { 220 | i++; 221 | node = node->next; 222 | } 223 | 224 | tmList *list2 = tmList_create(); 225 | list2->first = node; 226 | list2->last = list1->last; 227 | 228 | list1->last = node->prev; 229 | 230 | node->prev->next = NULL; 231 | node->prev = NULL; 232 | 233 | list2->count = list1->count - i; 234 | list1->count = i; 235 | 236 | return list2; 237 | 238 | } 239 | 240 | 241 | 242 | 243 | /************************************************************* 244 | * Function for swapping the values of two nodes in a 245 | * list structure 246 | *************************************************************/ 247 | static inline void tmListNode_swap(tmListNode *a, tmListNode *b); 248 | 249 | /************************************************************* 250 | * Function for merging two lists 251 | *************************************************************/ 252 | static inline tmList *tmList_merge(tmList *left, tmList *right, 253 | tmList_compare cmp); 254 | 255 | 256 | 257 | /************************************************************* 258 | * Function for swapping the values of two nodes in a 259 | * list structure 260 | *************************************************************/ 261 | static inline void tmListNode_swap(tmListNode *a, tmListNode *b) 262 | { 263 | void *temp = a->value; 264 | a->value = b->value; 265 | b->value = temp; 266 | } 267 | 268 | /************************************************************* 269 | * Function for merging two lists 270 | *************************************************************/ 271 | static inline tmList *tmList_merge(tmList *left, tmList *right, 272 | tmList_compare cmp) 273 | { 274 | tmList *result = tmList_create(); 275 | void *val = NULL; 276 | 277 | while (tmList_count(left) > 0 || tmList_count(right) > 0) { 278 | if (tmList_count(left) > 0 && tmList_count(right) > 0) { 279 | if (cmp(tmList_first(left), tmList_first(right)) <= 0) { 280 | val = tmList_shift(left); 281 | } 282 | else { 283 | val = tmList_shift(right); 284 | } 285 | tmList_push(result, val); 286 | } 287 | else if (tmList_count(left) > 0) { 288 | val = tmList_shift(left); 289 | tmList_push(result, val); 290 | } 291 | else if (tmList_count(right) > 0) { 292 | val = tmList_shift(right); 293 | tmList_push(result, val); 294 | } 295 | } 296 | 297 | return result; 298 | 299 | } 300 | 301 | /************************************************************* 302 | * Bubble sort algorithm 303 | *************************************************************/ 304 | int tmList_bubble_sort(tmList *list, tmList_compare cmp) 305 | { 306 | int sorted = 1; 307 | 308 | if (tmList_count(list) <= 1) { 309 | return 0; // Already sorted 310 | } 311 | 312 | do { 313 | sorted = 1; 314 | TMLIST_FOREACH(list, first, next, cur) { 315 | if (cur->next) { 316 | if (cmp(cur->value, cur->next->value) > 0) { 317 | tmListNode_swap(cur, cur->next); 318 | sorted = 0; 319 | } 320 | } 321 | } 322 | } while (!sorted); 323 | 324 | return 0; 325 | } 326 | 327 | 328 | /************************************************************* 329 | * Merge sort algorithm 330 | *************************************************************/ 331 | tmList *tmList_merge_sort(tmList *list, tmList_compare cmp) 332 | { 333 | tmList *result = NULL; 334 | 335 | if (tmList_count(list) <= 1) { 336 | return list; 337 | } 338 | 339 | tmList *left = tmList_create(); 340 | tmList *right = tmList_create(); 341 | int middle = tmList_count(list) / 2; 342 | 343 | TMLIST_FOREACH(list, first, next, cur) { 344 | if (middle > 0) { 345 | tmList_push(left, cur->value); 346 | } 347 | else { 348 | tmList_push(right, cur->value); 349 | } 350 | 351 | middle--; 352 | } 353 | 354 | tmList *sort_left = tmList_merge_sort(left, cmp); 355 | tmList *sort_right = tmList_merge_sort(right, cmp); 356 | 357 | if (sort_left != left) 358 | tmList_destroy(left); 359 | if (sort_right != right) 360 | tmList_destroy(right); 361 | 362 | result = tmList_merge(sort_left, sort_right, cmp); 363 | 364 | tmList_destroy(sort_left); 365 | tmList_destroy(sort_right); 366 | 367 | return result; 368 | 369 | } 370 | -------------------------------------------------------------------------------- /src/tmesh/test/geom_tests.c: -------------------------------------------------------------------------------- 1 | #include "tmesh/tmTypedefs.h" 2 | 3 | #include "tmesh/minunit.h" 4 | #include "tmesh/dbg.h" 5 | 6 | #include 7 | #include 8 | 9 | /************************************************************* 10 | * Unit test function for geometric functions 11 | *************************************************************/ 12 | char *test_geometric_functions() 13 | { 14 | tmDouble bbox_min[2] = { -1.23, -2.34 }; 15 | tmDouble bbox_max[2] = { 2.34, 1.23 }; 16 | 17 | tmDouble xy_1[2] = { 0.1, 0.1 }; 18 | tmDouble xy_2[2] = {-5.1, 0.1 }; 19 | tmDouble xy_3[2] = { 2.34,-1.1 }; 20 | 21 | tmDouble bbox_1_min[2] = { 1.0, -3.0 }; 22 | tmDouble bbox_1_max[2] = { 4.0, 1.1 }; 23 | 24 | tmDouble bbox_2_min[2] = { 4.0, 1.0 }; 25 | tmDouble bbox_2_max[2] = { 5.0, 2.0 }; 26 | 27 | tmDouble bbox_3_min[2] = {-1.1, -2.2 }; 28 | tmDouble bbox_3_max[2] = { 2.2, 1.1 }; 29 | 30 | mu_assert( IN_ON_BBOX(xy_1, bbox_min, bbox_max) == TRUE, 31 | "IN_ON_BBOX() gives wrong results."); 32 | mu_assert( IN_ON_BBOX(xy_2, bbox_min, bbox_max) == FALSE, 33 | "IN_ON_BBOX() gives wrong results."); 34 | mu_assert( IN_ON_BBOX(xy_3, bbox_min, bbox_max) == TRUE, 35 | "IN_ON_BBOX() gives wrong results."); 36 | 37 | mu_assert( IN_BBOX(xy_1, bbox_min, bbox_max) == TRUE, 38 | "IN_BBOX() gives wrong results."); 39 | mu_assert( IN_BBOX(xy_2, bbox_min, bbox_max) == FALSE, 40 | "IN_BBOX() gives wrong results."); 41 | mu_assert( IN_BBOX(xy_3, bbox_min, bbox_max) == FALSE, 42 | "IN_BBOX() gives wrong results."); 43 | 44 | mu_assert( ON_BBOX(xy_1, bbox_min, bbox_max) == FALSE, 45 | "ON_BBOX() gives wrong results."); 46 | mu_assert( ON_BBOX(xy_2, bbox_min, bbox_max) == FALSE, 47 | "ON_BBOX() gives wrong results."); 48 | mu_assert( ON_BBOX(xy_3, bbox_min, bbox_max) == TRUE, 49 | "ON_BBOX() gives wrong results."); 50 | 51 | 52 | mu_assert( BBOX_OVERLAP(bbox_1_min, bbox_1_max, bbox_min, bbox_max) == TRUE, 53 | "BBOX_OVERLAP() gives wrong results."); 54 | mu_assert( BBOX_OVERLAP(bbox_2_min, bbox_2_max, bbox_min, bbox_max) == FALSE, 55 | "BBOX_OVERLAP() gives wrong results."); 56 | mu_assert( BBOX_OVERLAP(bbox_3_min, bbox_3_max, bbox_min, bbox_max) == TRUE, 57 | "BBOX_OVERLAP() gives wrong results."); 58 | 59 | /*---------------------------------------------------------- 60 | | In segment 61 | ----------------------------------------------------------*/ 62 | tmDouble s1[2] = { 1.0, 1.0 }; 63 | tmDouble s2[2] = { 4.0, 1.0 }; 64 | tmDouble s3[2] = { 2.0, 1.0 }; 65 | tmDouble s4[2] = { 5.0, 1.0 }; 66 | 67 | mu_assert(ORIENTATION(s1, s2, s3) == 0, 68 | "ORIENTATION() gives wrong results."); 69 | 70 | mu_assert(IN_SEGMENT(s1, s2, s3) == TRUE, 71 | "IN_SEGMENT() gives wrong results."); 72 | 73 | mu_assert(IN_SEGMENT(s1, s2, s4) == FALSE, 74 | "IN_SEGMENT() gives wrong results."); 75 | 76 | mu_assert(IN_ON_SEGMENT(s1, s2, s1) == TRUE, 77 | "IN_ON_SEGMENT() gives wrong results."); 78 | 79 | mu_assert(IN_ON_SEGMENT(s1, s2, s4) == FALSE, 80 | "IN_ON_SEGMENT() gives wrong results."); 81 | 82 | 83 | /*---------------------------------------------------------- 84 | | Line intersection 85 | ----------------------------------------------------------*/ 86 | tmDouble n1[2] = { 1.0, 1.0 }; 87 | tmDouble n2[2] = { 4.0, 1.0 }; 88 | tmDouble n3[2] = { 2.0, 2.0 }; 89 | tmDouble n4[2] = { 6.0, 2.0 }; 90 | tmDouble n5[2] = { 8.0, 2.0 }; 91 | tmDouble n6[2] = { 2.0, 5.0 }; 92 | tmDouble n7[2] = { 6.0, 4.0 }; 93 | tmDouble n8[2] = { 7.0, 5.0 }; 94 | tmDouble n9[2] = { 8.0, 5.0 }; 95 | tmDouble n10[2] = { 9.0, 5.0 }; 96 | tmDouble n11[2] = { 2.0, 8.0 }; 97 | tmDouble n12[2] = { 6.0, 7.0 }; 98 | tmDouble n13[2] = { 6.0, 9.0 }; 99 | 100 | mu_assert(INTERSECTION_IN_LINES(n1, n2, n3, n4) == FALSE, 101 | "INTERSECTION_IN_LINES() gives wrong results."); 102 | mu_assert(INTERSECTION_IN_LINES(n6, n7, n6, n13) == FALSE, 103 | "INTERSECTION_IN_LINES() gives wrong results."); 104 | 105 | mu_assert(INTERSECTION_IN_LINES(n6, n13, n11, n12) == TRUE, 106 | "INTERSECTION_IN_LINES() gives wrong results."); 107 | mu_assert(INTERSECTION_IN_LINES(n5, n9, n8, n10) == TRUE, 108 | "INTERSECTION_IN_LINES() gives wrong results."); 109 | 110 | return NULL; 111 | } /* test_geometric_functions() */ 112 | -------------------------------------------------------------------------------- /src/tmesh/test/geom_tests.h: -------------------------------------------------------------------------------- 1 | #ifndef geom_tests_h 2 | #define geom_tests_h 3 | /************************************************************* 4 | * Unit test function for geometric functions 5 | *************************************************************/ 6 | char *test_geometric_functions(); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/tmesh/test/tmList_tests.c: -------------------------------------------------------------------------------- 1 | #include "tmesh/minunit.h" 2 | #include "tmesh/tmList.h" 3 | #include 4 | #include "tmList_tests.h" 5 | 6 | /************************************************************* 7 | * Definition of unit test variables 8 | *************************************************************/ 9 | static tmList *list = NULL; 10 | static tmList *list_jn = NULL; 11 | char *test1= "test1 data"; 12 | char *test2= "test2 data"; 13 | char *test3= "test3 data"; 14 | char *test4= "test4 data"; 15 | 16 | /************************************************************* 17 | * Definition of unit test functions 18 | *************************************************************/ 19 | char *test_tmList_create() 20 | { 21 | list = tmList_create(); 22 | mu_assert(list != NULL, "Failed to create list."); 23 | 24 | list_jn = tmList_create(); 25 | mu_assert(list_jn != NULL, "Failed to create list."); 26 | 27 | return NULL; 28 | } 29 | 30 | char *test_tmList_push_pop() 31 | { 32 | tmList_push(list, test1); 33 | mu_assert(tmList_last(list) == test1, "Wrong last value."); 34 | 35 | tmList_push(list, test2); 36 | mu_assert(tmList_last(list) == test2, "Wrong last value."); 37 | 38 | tmList_push(list, test3); 39 | mu_assert(tmList_last(list) == test3, "Wrong last value."); 40 | mu_assert(tmList_count(list) == 3, "Wrong count on push."); 41 | 42 | char *val = tmList_pop(list); 43 | mu_assert(val == test3, "Wrong value on pop."); 44 | 45 | val = tmList_pop(list); 46 | mu_assert(val == test2, "Wrong value on pop."); 47 | 48 | val = tmList_pop(list); 49 | mu_assert(val == test1, "Wrong value on pop."); 50 | mu_assert(tmList_count(list) == 0, "Wrong count after pop."); 51 | 52 | return NULL; 53 | } 54 | 55 | char *test_tmList_unshift() 56 | { 57 | tmList_unshift(list, test1); 58 | mu_assert(tmList_first(list) == test1, "Wrong first value."); 59 | 60 | tmList_unshift(list, test2); 61 | mu_assert(tmList_first(list) == test2, "Wrong first value."); 62 | 63 | tmList_unshift(list, test3); 64 | mu_assert(tmList_first(list) == test3, "Wrong first value."); 65 | mu_assert(tmList_count(list) == 3, "Wrong count on unshift."); 66 | 67 | return NULL; 68 | } 69 | 70 | char *test_tmList_remove() 71 | { 72 | char *val = tmList_remove(list, list->first->next); 73 | mu_assert(val == test2, "Wrong removed element."); 74 | mu_assert(tmList_count(list) == 2, "Wrong count after remove."); 75 | mu_assert(tmList_first(list) == test3, "Wrong first after remove."); 76 | mu_assert(tmList_last(list) == test1, "Wrong last after remove."); 77 | 78 | return NULL; 79 | } 80 | 81 | char *test_tmList_shift() 82 | { 83 | mu_assert(tmList_count(list) != 0, "Wrong count before shift."); 84 | 85 | char *val = tmList_shift(list); 86 | mu_assert(val == test3, "Wrong value on shift."); 87 | 88 | val = tmList_shift(list); 89 | mu_assert(val == test1, "Wrong value on shift."); 90 | mu_assert(tmList_count(list) == 0, "Wrong count after shift."); 91 | 92 | return NULL; 93 | } 94 | 95 | char *test_tmList_destroy() 96 | { 97 | tmList_clear_destroy(list); 98 | 99 | return NULL; 100 | } 101 | 102 | 103 | char *test_tmList_join() 104 | { 105 | tmList_push(list, test1); 106 | mu_assert(tmList_last(list) == test1, "Wrong last value."); 107 | 108 | tmList_push(list, test2); 109 | mu_assert(tmList_last(list) == test2, "Wrong last value."); 110 | 111 | tmList_push(list_jn, test3); 112 | mu_assert(tmList_last(list_jn) == test3, "Wrong last value."); 113 | 114 | tmList_push(list_jn, test4); 115 | mu_assert(tmList_last(list_jn) == test4, "Wrong last value."); 116 | 117 | tmList_join(list, list_jn); 118 | mu_assert(tmList_count(list) == 4, "Wrong join count."); 119 | mu_assert(tmList_first(list) == test1, "Wrong join first value."); 120 | mu_assert(list->first->next->next->value == test3, "Wrong join first value."); 121 | mu_assert(tmList_last(list) == test4, "Wrong join first value."); 122 | 123 | char *val; 124 | val = tmList_pop(list); 125 | mu_assert(val == test4, "Wrong value on pop."); 126 | 127 | val = tmList_pop(list); 128 | mu_assert(val == test3, "Wrong value on pop."); 129 | 130 | val = tmList_pop(list); 131 | mu_assert(val == test2, "Wrong value on pop."); 132 | 133 | val = tmList_pop(list); 134 | mu_assert(val == test1, "Wrong value on pop."); 135 | 136 | return NULL; 137 | 138 | } 139 | 140 | 141 | char *test_tmList_split() 142 | { 143 | 144 | tmList *test_tmList = tmList_create(); 145 | double test_data[5] = {1.0, 2.0, 3.0, 4.0, 5.0}; 146 | 147 | int i; 148 | for (i = 0; i < 5; i++) 149 | tmList_push(test_tmList, &test_data[i]); 150 | 151 | mu_assert( test_tmList->first->prev == NULL, 152 | "Wrong list definition."); 153 | mu_assert( test_tmList->last->next == NULL, 154 | "Wrong list definition."); 155 | 156 | tmList *split_tmList = tmList_split(test_tmList, 2); 157 | 158 | mu_assert( *(double*)(split_tmList->first->value) == 3.0, 159 | "Failed to split list."); 160 | mu_assert( *(double*)(split_tmList->last->value) == 5.0, 161 | "Failed to split list."); 162 | 163 | mu_assert( *(double*)(test_tmList->first->value) == 1.0, 164 | "Failed to split list."); 165 | mu_assert( *(double*)(test_tmList->last->value) == 2.0, 166 | "Failed to split list."); 167 | 168 | mu_assert( split_tmList->first->prev == NULL, 169 | "Failed to split list."); 170 | mu_assert( test_tmList->last->next == NULL, 171 | "Failed to split list."); 172 | mu_assert( test_tmList->count == 2, 173 | "Failed to split list."); 174 | mu_assert( split_tmList->count == 3, 175 | "Failed to split list."); 176 | 177 | tmList_destroy(split_tmList); 178 | 179 | split_tmList = tmList_split(test_tmList, 0); 180 | 181 | mu_assert( split_tmList == test_tmList, 182 | "Failed to split list."); 183 | 184 | split_tmList = tmList_split(test_tmList, test_tmList->count-1); 185 | 186 | mu_assert( *(double*)(split_tmList->first->value) == 2.0, 187 | "Failed to split list."); 188 | mu_assert( *(double*)(split_tmList->last->value) == 2.0, 189 | "Failed to split list."); 190 | mu_assert( *(double*)(test_tmList->first->value) == 1.0, 191 | "Failed to split list."); 192 | mu_assert( *(double*)(test_tmList->last->value) == 1.0, 193 | "Failed to split list."); 194 | mu_assert( split_tmList->first->prev == NULL, 195 | "Failed to split list."); 196 | mu_assert( test_tmList->last->next == NULL, 197 | "Failed to split list."); 198 | 199 | mu_assert( test_tmList->count == 1, 200 | "Failed to split list."); 201 | mu_assert( split_tmList->count == 1, 202 | "Failed to split list."); 203 | 204 | tmList_destroy(split_tmList); 205 | 206 | 207 | split_tmList = tmList_split(test_tmList, 0); 208 | 209 | mu_assert( split_tmList == test_tmList, 210 | "Failed to split list."); 211 | 212 | 213 | tmList_destroy(test_tmList); 214 | 215 | return NULL; 216 | } 217 | -------------------------------------------------------------------------------- /src/tmesh/test/tmList_tests.h: -------------------------------------------------------------------------------- 1 | #ifndef tmList_tests_h 2 | #define tmList_tests_h 3 | 4 | char *test_tmList_create(); 5 | char *test_tmList_push_pop(); 6 | char *test_tmList_unshift(); 7 | char *test_tmList_remove(); 8 | char *test_tmList_shift(); 9 | char *test_tmList_destroy(); 10 | char *test_tmList_join(); 11 | char *test_tmList_split(); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /src/tmesh/test/tmParam_tests.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "tmParam_tests.h" 5 | 6 | //const char *testfile = "/datadisk/Code/C-Code/tmesh/share/files/example.para"; 7 | const char *testfile = "/datadisk/Code/C-Code/tmesh/share/files/comment_test.para"; 8 | 9 | /************************************************************* 10 | * Unit test function to handle creation and 11 | * destruction of bstrings 12 | *************************************************************/ 13 | char *test_tmParam_readfile() 14 | { 15 | int i; 16 | bstring *ptr = NULL; 17 | tmParam *file = tmParam_create( testfile ); 18 | 19 | /*---------------------------------------------------------- 20 | | Return all lines without '#' Comment specifier 21 | ----------------------------------------------------------*/ 22 | struct bstrList *test_1 = tmParam_popLinesWith(file->txtlist, "#"); 23 | 24 | ptr = test_1->entry; 25 | bstring bcmp_1 = bfromcstr( "NODES" ); 26 | 27 | for (i = 0; i < test_1->qty; i++) 28 | mu_assert( binstr(ptr[i], 0, bcmp_1) == BSTR_ERR, 29 | " failed."); 30 | 31 | /*---------------------------------------------------------- 32 | | Return all lines with 'Define nodes' specifier 33 | ----------------------------------------------------------*/ 34 | struct bstrList *test_2 = tmParam_getLinesWith(file->txtlist, 35 | "Define nodes:"); 36 | 37 | ptr = test_2->entry; 38 | bstring bcmp_2 = bfromcstr( "Define nodes:" ); 39 | 40 | for (i = 0; i < test_2->qty; i++) 41 | mu_assert(binstr(ptr[i], 0, bcmp_2) != BSTR_ERR, 42 | " failed."); 43 | 44 | /*---------------------------------------------------------- 45 | | Return integer / float / bstring parameter 46 | ----------------------------------------------------------*/ 47 | int int_param, check; 48 | double dbl_param; 49 | bstring bstr_param; 50 | 51 | check = tmParam_extractParam(file->txtlist, 52 | "Number of quadtree elements:", 0, &int_param); 53 | mu_assert( check == 1, " failed."); 54 | mu_assert( int_param == 50, " failed."); 55 | 56 | check = tmParam_extractParam(file->txtlist, 57 | "Global element size:", 1, &dbl_param); 58 | mu_assert( check == 1, " failed."); 59 | mu_assert( dbl_param == 0.5, 60 | " failed."); 61 | 62 | check = tmParam_extractParam(file->txtlist, 63 | "Mesh bounding box:", 2, &bstr_param); 64 | mu_assert( check == 1, " failed."); 65 | mu_assert( strcmp( " -10.0, -10.0, 20.0, 20.0", bstr_param->data) == 0, 66 | " failed."); 67 | 68 | /*---------------------------------------------------------- 69 | | Return array from parameter 70 | ----------------------------------------------------------*/ 71 | int *int_array; 72 | check = tmParam_extractArray(file->txtlist, 73 | "Mesh bounding box:", 0, &int_array); 74 | mu_assert( check == 1, " failed."); 75 | mu_assert( int_array[0] == -10 , " failed."); 76 | mu_assert( int_array[2] == 20 , " failed."); 77 | free(int_array); 78 | 79 | double *dbl_array; 80 | check = tmParam_extractArray(file->txtlist, 81 | "Mesh bounding box:", 1, &dbl_array); 82 | mu_assert( check == 1, " failed."); 83 | mu_assert( dbl_array[0] == -10.0 , " failed."); 84 | mu_assert( dbl_array[2] == 20.0 , " failed."); 85 | free(dbl_array); 86 | 87 | /* THIS IS NOT WORKING YET! 88 | struct bstrList *str_array; 89 | check = tmParam_extractArray(file->txtlist, 90 | "Mesh bounding box:", 2, &str_array); 91 | mu_assert( check == 1, " failed."); 92 | mu_assert( str_array->qty == 4, " failed."); 93 | bstrListDestroy(str_array); */ 94 | 95 | /*---------------------------------------------------------- 96 | | Read node coordinates 97 | ----------------------------------------------------------*/ 98 | tmDouble (*nodes)[2]; 99 | int nNodes; 100 | tmParam_readNodeCoords(file->txtlist, 101 | &nodes, &nNodes); 102 | mu_assert( nodes[0][0] == 1.0, 103 | " failed."); 104 | mu_assert( nodes[0][1] == 1.0, 105 | " failed."); 106 | mu_assert( nodes[5][0] == 2.0, 107 | " failed."); 108 | mu_assert( nodes[5][1] == 4.0, 109 | " failed."); 110 | free(nodes); 111 | 112 | /*---------------------------------------------------------- 113 | | Read exterior boundary edges 114 | ----------------------------------------------------------*/ 115 | int (*bdryEdges)[2]; 116 | int *bdryEdgeMarker; 117 | tmDouble *bdryRefinement; 118 | int nBdryEdges; 119 | int bdryMarker; 120 | 121 | tmParam_readExtBdryData(file->txtlist, 122 | &bdryEdges, &bdryEdgeMarker, &bdryRefinement, 123 | &nBdryEdges, &bdryMarker); 124 | mu_assert( bdryMarker == 1, 125 | " failed."); 126 | mu_assert( nBdryEdges == 4, 127 | " failed."); 128 | mu_assert( bdryEdges[1][1] == 2, 129 | " failed."); 130 | mu_assert( bdryEdges[2][0] == 2, 131 | " failed."); 132 | mu_assert( bdryEdges[0][0] == 0, 133 | " failed."); 134 | mu_assert( bdryEdgeMarker[0] == 0, 135 | " failed."); 136 | mu_assert( bdryEdgeMarker[2] == 0, 137 | " failed."); 138 | mu_assert( bdryRefinement[2] == 1.4, 139 | " failed."); 140 | free(bdryEdges); 141 | free(bdryEdgeMarker); 142 | free(bdryRefinement); 143 | 144 | 145 | 146 | /*---------------------------------------------------------- 147 | | Read exterior boundary edges 148 | ----------------------------------------------------------*/ 149 | int (**intrEdges)[2]; 150 | int **intrEdgeMarkers; 151 | tmDouble **intrEdgeRefinements; 152 | int *nIntrEdges; 153 | int *intrBdryMarkers; 154 | int nIntrBdrys; 155 | 156 | tmParam_readIntBdryData(file->txtlist, 157 | &intrEdges, &intrEdgeMarkers, 158 | &intrEdgeRefinements, 159 | &nIntrEdges, &intrBdryMarkers, 160 | &nIntrBdrys); 161 | 162 | /* 163 | int j; 164 | for (j = 0; j < nIntrBdrys; j++) 165 | { 166 | tmPrint("INTERIOR BOUNDARY %d: %d EDGES, MARKER %d", 167 | j, nIntrEdges[j], intrBdryMarkers[j]); 168 | 169 | for (i = 0; i < nIntrEdges[j]; i++) 170 | tmPrint(" %d: (%d, %d), %d, %.3f", 171 | i, intrEdges[j][i][0], intrEdges[j][i][1], 172 | intrEdgeMarkers[j][i], intrEdgeRefinements[j][i]); 173 | } 174 | */ 175 | 176 | for (i = 0; i < nIntrBdrys; i++) 177 | { 178 | free(intrEdges[i]); 179 | free(intrEdgeMarkers[i]); 180 | free(intrEdgeRefinements[i]); 181 | } 182 | free(intrEdges); 183 | free(intrEdgeMarkers); 184 | free(intrEdgeRefinements); 185 | free(nIntrEdges); 186 | free(intrBdryMarkers); 187 | 188 | 189 | 190 | 191 | bdestroy(bstr_param); 192 | tmParam_destroy( file ); 193 | bdestroy( bcmp_1 ); 194 | bdestroy( bcmp_2 ); 195 | bstrListDestroy( test_1 ); 196 | bstrListDestroy( test_2 ); 197 | 198 | return NULL; 199 | } 200 | 201 | 202 | /************************************************************* 203 | * Read a file and clear all strings behind a comment 204 | * identifier 205 | *************************************************************/ 206 | char *test_tmParam_comments() 207 | { 208 | int i; 209 | 210 | tmParam *file = tmParam_create( testfile ); 211 | 212 | /*---------------------------------------------------------- 213 | | Remove all comments from the file 214 | ----------------------------------------------------------*/ 215 | bstring comment_fltr = bfromcstr("#"); 216 | struct bstrList *test_1 = tmParam_removeComments(file->txtlist, 217 | comment_fltr->data); 218 | bstring *fl_ptr = test_1->entry; 219 | 220 | for (i = 0; i < test_1->qty; i++) 221 | { 222 | mu_assert( binstr(fl_ptr[i], 0, comment_fltr) == BSTR_ERR, 223 | " failed."); 224 | } 225 | 226 | /*---------------------------------------------------------- 227 | | Free memory 228 | ----------------------------------------------------------*/ 229 | bstrListDestroy( test_1 ); 230 | bdestroy( comment_fltr ); 231 | tmParam_destroy( file ); 232 | 233 | return NULL; 234 | } 235 | -------------------------------------------------------------------------------- /src/tmesh/test/tmParam_tests.h: -------------------------------------------------------------------------------- 1 | #ifndef tmParam_tests_h 2 | #define tmParam_tests_h 3 | 4 | char *test_tmParam_readfile(); 5 | 6 | char *test_tmParam_comments(); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/tmesh/test/tmesh_cylinder.c: -------------------------------------------------------------------------------- 1 | #include "tmesh/tmNode.h" 2 | #include "tmesh/tmEdge.h" 3 | #include "tmesh/tmMesh.h" 4 | #include "tmesh/tmBdry.h" 5 | 6 | #include "tmesh/dbg.h" 7 | 8 | #include "tmesh_cylinder.h" 9 | 10 | #include 11 | #include 12 | #define _USE_MATH_DEFINES 13 | #include 14 | #include 15 | 16 | /************************************************************* 17 | * 18 | *************************************************************/ 19 | static inline tmDouble size_fun( tmDouble xy[2] ) 20 | { 21 | tmDouble x0 = 200.0; 22 | tmDouble y0 = 200.0; 23 | 24 | tmDouble dx = x0 - xy[0]; 25 | tmDouble dy = y0 - xy[1]; 26 | tmDouble r2 = dx*dx + dy*dy; 27 | 28 | if (xy[0] < 500.0) 29 | return 40.0 - 39.0 * exp(-0.00001*r2); 30 | else 31 | return 25. + 0.01*xy[0]; 32 | } 33 | 34 | /************************************************************* 35 | * Function to create a mesh with a cylinder 36 | *************************************************************/ 37 | char *test_mesh_cylinder() 38 | { 39 | tmDouble xy_min[2] = { -1.0, -1.0 }; 40 | tmDouble xy_max[2] = { 2201.0, 411.0 }; 41 | tmMesh *mesh = tmMesh_create(xy_min, xy_max, 25, 50., size_fun); 42 | 43 | /*-------------------------------------------------------- 44 | | exterior boundary 45 | --------------------------------------------------------*/ 46 | tmDouble xy_e0[2] = { 0.0, 0.0 }; 47 | tmDouble xy_e1[2] = { 2200.0, 0.0 }; 48 | tmDouble xy_e2[2] = { 2200.0, 410.0 }; 49 | tmDouble xy_e3[2] = { 0.0, 410.0 }; 50 | 51 | tmNode *n_e0 = tmNode_create(mesh, xy_e0); 52 | tmNode *n_e1 = tmNode_create(mesh, xy_e1); 53 | tmNode *n_e2 = tmNode_create(mesh, xy_e2); 54 | tmNode *n_e3 = tmNode_create(mesh, xy_e3); 55 | 56 | tmBdry *bdry_ext = tmMesh_addBdry(mesh, FALSE, 0); 57 | 58 | tmEdge *e_e0 = tmBdry_edgeCreate(bdry_ext, n_e0, n_e1, 0, 1.0); 59 | tmEdge *e_e1 = tmBdry_edgeCreate(bdry_ext, n_e1, n_e2, 1, 1.0); 60 | tmEdge *e_e2 = tmBdry_edgeCreate(bdry_ext, n_e2, n_e3, 2, 1.0); 61 | tmEdge *e_e3 = tmBdry_edgeCreate(bdry_ext, n_e3, n_e0, 3, 1.0); 62 | 63 | 64 | /*-------------------------------------------------------- 65 | | interior boundary 66 | --------------------------------------------------------*/ 67 | tmDouble xy_center[2] = { 200.0, 200.0 }; 68 | int n_segs = 60; 69 | tmDouble radius = 50; 70 | 71 | tmNode *n_circ[n_segs]; 72 | tmEdge *e_circ[n_segs]; 73 | 74 | tmBdry *bdry_int = tmMesh_addBdry(mesh, TRUE, 1); 75 | 76 | int i; 77 | for (i=0; i ----------------------------------------------\n"); 101 | printf("> cylinder mesh performance test \n"); 102 | printf("> ----------------------------------------------\n"); 103 | printf("> Number of elements: %d\n", mesh->no_tris); 104 | printf("> Meshing time : %e sec\n", (double) (tic_2 - tic_1) / CLOCKS_PER_SEC ); 105 | printf("> ----------------------------------------------\n"); 106 | 107 | /*-------------------------------------------------------- 108 | | Print the mesh data 109 | --------------------------------------------------------*/ 110 | tmMesh_printMesh(mesh); 111 | 112 | tmMesh_destroy(mesh); 113 | 114 | return NULL; 115 | 116 | } /* test_mesh_cylinder() */ 117 | -------------------------------------------------------------------------------- /src/tmesh/test/tmesh_cylinder.h: -------------------------------------------------------------------------------- 1 | #ifndef tmesh_tests_h 2 | #define tmesh_tests_h 3 | 4 | /************************************************************* 5 | * Function to create a mesh with a cylinder 6 | *************************************************************/ 7 | char *test_mesh_cylinder(); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /src/tmesh/test/tmesh_examples.c: -------------------------------------------------------------------------------- 1 | #include "tmesh/tmNode.h" 2 | #include "tmesh/tmEdge.h" 3 | #include "tmesh/tmTri.h" 4 | #include "tmesh/tmBdry.h" 5 | #include "tmesh/tmMesh.h" 6 | #include "tmesh/tmQtree.h" 7 | #include "tmesh/tmFront.h" 8 | #include "tmesh/tmList.h" 9 | 10 | #include "tmesh/minunit.h" 11 | #include "tmesh/dbg.h" 12 | 13 | #include "tmesh_tests.h" 14 | 15 | #include 16 | #include 17 | #define _USE_MATH_DEFINES 18 | #include 19 | #include 20 | 21 | /************************************************************ 22 | * Example 1) 23 | * Simple mesh with constant size 24 | ************************************************************/ 25 | char *test_example_1() 26 | { 27 | /*-------------------------------------------------------- 28 | | 1) Define the mesh structure. 29 | | 30 | | xyMin, xyMax: The bounding box of the entire mesh 31 | | nElemQtree : number of elements in a QuadTree, 32 | | until it will be refined 33 | | Has only influence on the performance. 34 | | globSize : A number > 0 defining the global 35 | | element size of the mesh 36 | --------------------------------------------------------*/ 37 | int nElemQtree = 50; 38 | tmDouble globSize = 1.0; 39 | tmDouble xyMin[2] = {-10.0,-10.0 }; 40 | tmDouble xyMax[2] = { 20.0, 20.0 }; 41 | 42 | tmMesh *mesh = tmMesh_create(xyMin, xyMax, nElemQtree, 43 | globSize, NULL); 44 | 45 | /*-------------------------------------------------------- 46 | | 2) Define the mesh's exterior boundary. 47 | | The "FALSE" flag simply defines, that this boundary 48 | | is not an interior boundary. 49 | | The 0 is an identifier for this boundary, which is 50 | | given as output later, as the mesh is printed out. 51 | --------------------------------------------------------*/ 52 | tmBdry *bdry_ext = tmMesh_addBdry(mesh, FALSE, 0); 53 | 54 | /*-------------------------------------------------------- 55 | | 3) Define the exterior boundary edge nodes. 56 | | Each boundary edge segment consists of two directed 57 | | nodes (n1,n2), which must be defined first. 58 | | IMPORTANT: Exterior boundary edges must be defined 59 | | in a counter-clockwise manner. 60 | --------------------------------------------------------*/ 61 | tmDouble xy0[2] = { -1.0, -1.0 }; 62 | tmDouble xy1[2] = { 16.0, 7.0 }; 63 | tmDouble xy2[2] = { -1.0, 10.0 }; 64 | 65 | tmNode *n0 = tmNode_create(mesh, xy0); 66 | tmNode *n1 = tmNode_create(mesh, xy1); 67 | tmNode *n2 = tmNode_create(mesh, xy2); 68 | 69 | /*-------------------------------------------------------- 70 | | 4) Define the exterior boundary edge segments. 71 | | The function takes the following parameters: 72 | 73 | | > tmBdry_edgeCreate(bdry_ext, n0, n1, marker, f) 74 | | 75 | | marker : This is a further indicator which 76 | | can be applied to each edge segment 77 | | Here, all segments have the same 78 | | indicator, but it could also be 79 | | chosen in an arbitrary manner, 80 | | depending on the application the 81 | | mesh will be used for. 82 | | This value is not related to the 83 | | boundary identifier, which was also 84 | | chosen to be 1 above. 85 | | refinement f : This factor > 1.0 defines the 86 | | refinement of the mesh elements near 87 | | the first edge node n1. Increasing 88 | | the value will lead to a larger 89 | | refinement of elements near edges 90 | | with sharp angles. 91 | --------------------------------------------------------*/ 92 | tmEdge *e0 = tmBdry_edgeCreate(bdry_ext, n0, n1, 0, 1.2); 93 | tmEdge *e1 = tmBdry_edgeCreate(bdry_ext, n1, n2, 0, 1.2); 94 | tmEdge *e2 = tmBdry_edgeCreate(bdry_ext, n2, n0, 0, 1.2); 95 | 96 | /*-------------------------------------------------------- 97 | | 2) Define the mesh's interior boundary. 98 | | The "TRUE" flag defines, that this boundary 99 | | is an interior boundary. 100 | | The 1 is an identifier for this boundary, which is 101 | | given as output later, as the mesh is printed out. 102 | --------------------------------------------------------*/ 103 | tmBdry *bdry_int = tmMesh_addBdry(mesh, TRUE, 1); 104 | 105 | /*-------------------------------------------------------- 106 | | 3) Define the interior boundary edge nodes. 107 | --------------------------------------------------------*/ 108 | tmDouble xy3[2] = { 1.0, 4.0 }; 109 | tmDouble xy4[2] = { 6.0, 8.0 }; 110 | tmDouble xy5[2] = { 6.0, 4.0 }; 111 | 112 | tmNode *n3 = tmNode_create(mesh, xy3); 113 | tmNode *n4 = tmNode_create(mesh, xy4); 114 | tmNode *n5 = tmNode_create(mesh, xy5); 115 | 116 | /*-------------------------------------------------------- 117 | | 4) Define the interior boundary edge segments. 118 | | IMPORTANT: Interior boundary edges must be defined 119 | | in a clockwise manner. 120 | --------------------------------------------------------*/ 121 | tmEdge *e3 = tmBdry_edgeCreate(bdry_int, n3, n4, 1, 1.6); 122 | tmEdge *e4 = tmBdry_edgeCreate(bdry_int, n4, n5, 1, 1.6); 123 | tmEdge *e5 = tmBdry_edgeCreate(bdry_int, n5, n3, 1, 1.6); 124 | 125 | /*-------------------------------------------------------- 126 | | Create mesh 127 | --------------------------------------------------------*/ 128 | clock_t tic_1 = clock(); 129 | tmMesh_ADFMeshing(mesh); 130 | clock_t tic_2 = clock(); 131 | 132 | /*-------------------------------------------------------- 133 | | Print the mesh data 134 | --------------------------------------------------------*/ 135 | tmMesh_printMesh(mesh); 136 | 137 | tmPrint("----------------------------------------------\n"); 138 | tmPrint("Example 1 performance test \n"); 139 | tmPrint("----------------------------------------------\n"); 140 | tmPrint("Number of elements: %d\n", mesh->no_tris); 141 | tmPrint("Meshing time : %e sec\n", 142 | (double) (tic_2 - tic_1) / CLOCKS_PER_SEC ); 143 | tmPrint("----------------------------------------------\n"); 144 | 145 | tmMesh_destroy(mesh); 146 | 147 | return NULL; 148 | 149 | } /* test_example_1() */ 150 | 151 | /************************************************************ 152 | * Example 2) 153 | * Simple mesh with user defined size function 154 | * 155 | * First, we need to define a size function: 156 | ************************************************************/ 157 | static inline tmDouble sizeFunExample( tmDouble xy[2] ) 158 | { 159 | tmDouble sizeFac = 1.5; 160 | tmDouble dx = 8.0 - xy[0]; 161 | tmDouble dy = 6.0 - xy[1]; 162 | return sizeFac * (0.46 - 0.41 * exp(-0.05*(dx*dx+dy*dy))); 163 | } 164 | char *test_example_2() 165 | { 166 | /*-------------------------------------------------------- 167 | | 1) Define the mesh structure. 168 | | The size function is now passed to the mesh as 169 | | argument on its creation. 170 | | The rest is done as before. 171 | --------------------------------------------------------*/ 172 | int nElemQtree = 50; 173 | tmDouble globSize = 1.0; 174 | tmDouble xyMin[2] = {-10.0,-10.0 }; 175 | tmDouble xyMax[2] = { 20.0, 20.0 }; 176 | 177 | tmMesh *mesh = tmMesh_create(xyMin, xyMax, nElemQtree, 178 | globSize, sizeFunExample); 179 | 180 | /*-------------------------------------------------------- 181 | | 2) Define the mesh's exterior boundary. 182 | --------------------------------------------------------*/ 183 | tmBdry *bdry_ext = tmMesh_addBdry(mesh, FALSE, 0); 184 | 185 | /*-------------------------------------------------------- 186 | | 3) Define the exterior boundary edge nodes. 187 | --------------------------------------------------------*/ 188 | tmDouble xy0[2] = { -1.0, -1.0 }; 189 | tmDouble xy1[2] = { 16.0, 7.0 }; 190 | tmDouble xy2[2] = { -1.0, 10.0 }; 191 | 192 | tmNode *n0 = tmNode_create(mesh, xy0); 193 | tmNode *n1 = tmNode_create(mesh, xy1); 194 | tmNode *n2 = tmNode_create(mesh, xy2); 195 | 196 | /*-------------------------------------------------------- 197 | | 4) Define the exterior boundary edge segments. 198 | --------------------------------------------------------*/ 199 | tmEdge *e0 = tmBdry_edgeCreate(bdry_ext, n0, n1, 0, 1.2); 200 | tmEdge *e1 = tmBdry_edgeCreate(bdry_ext, n1, n2, 0, 1.2); 201 | tmEdge *e2 = tmBdry_edgeCreate(bdry_ext, n2, n0, 0, 1.2); 202 | 203 | /*-------------------------------------------------------- 204 | | 2) Define the mesh's interior boundary. 205 | --------------------------------------------------------*/ 206 | tmBdry *bdry_int = tmMesh_addBdry(mesh, TRUE, 1); 207 | 208 | /*-------------------------------------------------------- 209 | | 3) Define the interior boundary edge nodes. 210 | --------------------------------------------------------*/ 211 | tmDouble xy3[2] = { 1.0, 4.0 }; 212 | tmDouble xy4[2] = { 6.0, 8.0 }; 213 | tmDouble xy5[2] = { 6.0, 4.0 }; 214 | 215 | tmNode *n3 = tmNode_create(mesh, xy3); 216 | tmNode *n4 = tmNode_create(mesh, xy4); 217 | tmNode *n5 = tmNode_create(mesh, xy5); 218 | 219 | /*-------------------------------------------------------- 220 | | 4) Define the interior boundary edge segments. 221 | --------------------------------------------------------*/ 222 | tmEdge *e3 = tmBdry_edgeCreate(bdry_int, n3, n4, 1, 1.6); 223 | tmEdge *e4 = tmBdry_edgeCreate(bdry_int, n4, n5, 1, 1.6); 224 | tmEdge *e5 = tmBdry_edgeCreate(bdry_int, n5, n3, 1, 1.6); 225 | 226 | /*-------------------------------------------------------- 227 | | Create mesh 228 | --------------------------------------------------------*/ 229 | clock_t tic_1 = clock(); 230 | tmMesh_ADFMeshing(mesh); 231 | clock_t tic_2 = clock(); 232 | 233 | /*-------------------------------------------------------- 234 | | Print the mesh data 235 | --------------------------------------------------------*/ 236 | tmMesh_printMesh(mesh); 237 | 238 | tmPrint("----------------------------------------------\n"); 239 | tmPrint("Example 2 performance test \n"); 240 | tmPrint("----------------------------------------------\n"); 241 | tmPrint("Number of elements: %d\n", mesh->no_tris); 242 | tmPrint("Meshing time : %e sec\n", 243 | (double) (tic_2 - tic_1) / CLOCKS_PER_SEC ); 244 | tmPrint("----------------------------------------------\n"); 245 | 246 | tmMesh_destroy(mesh); 247 | 248 | return NULL; 249 | 250 | 251 | 252 | } /* test_example_2() */ 253 | -------------------------------------------------------------------------------- /src/tmesh/test/tmesh_examples.h: -------------------------------------------------------------------------------- 1 | #ifndef tmesh_examples_h 2 | #define tmesh_examples_h 3 | 4 | /************************************************************ 5 | * Example 1) 6 | * Simple mesh with constant size 7 | ************************************************************/ 8 | char *test_example_1(); 9 | 10 | /************************************************************ 11 | * Example 2) 12 | * Simple mesh with user defined size function 13 | ************************************************************/ 14 | char *test_example_2(); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/tmesh/test/tmesh_tests.h: -------------------------------------------------------------------------------- 1 | #ifndef tmesh_tests_h 2 | #define tmesh_tests_h 3 | 4 | /************************************************************* 5 | * Unit test function to handle creation and 6 | * destruction of a mesh structure 7 | *************************************************************/ 8 | char *test_mesh_create_destroy(); 9 | 10 | /************************************************************ 11 | * Unit test function to test if an object can be located 12 | * within the domain 13 | ************************************************************/ 14 | char *test_tmMesh_objInside(); 15 | 16 | /************************************************************* 17 | * Unit test function to the boundary refinement 18 | ************************************************************/ 19 | char *test_tmBdry_refine(); 20 | 21 | /************************************************************* 22 | * Unit test function to handle the tmQtree structure 23 | * 24 | * Maximum number of qtree-objects must be set to 3 ! 25 | * in order to get this test running 26 | ************************************************************/ 27 | char *test_tmQtree(); 28 | 29 | /************************************************************ 30 | * Unit test function to handle the tmQtree structure 31 | * 32 | * Maximum number of qtree-objects must be set to 2 33 | * in order to get this test running 34 | ************************************************************/ 35 | char *test_tmQtree_2(); 36 | 37 | /************************************************************* 38 | * Unit test function to handle the tmQtree performance 39 | ************************************************************/ 40 | char *test_tmQtree_performance(); 41 | 42 | /************************************************************* 43 | * Unit test function to handle the tmQtree performance 44 | ************************************************************/ 45 | char *test_tmQtree_performance2(); 46 | 47 | /************************************************************* 48 | * Unit test function for the triangle intersection 49 | ************************************************************/ 50 | char *test_tmTri_intersection(); 51 | 52 | /************************************************************* 53 | * Unit test function for the advancing front algorithm 54 | ************************************************************/ 55 | char *test_tmFront_init(); 56 | char *test_tmFront_advance(); 57 | char *test_tmFront_simpleMesh(); 58 | char *test_tmFront_simpleMesh2(); 59 | char *test_tmFront_innerOuterMesh(); 60 | char *test_tmFront_tMesh(); 61 | 62 | /************************************************************ 63 | * Unit test function to handle the automatic sizeFunction 64 | * at boundary edges 65 | ************************************************************/ 66 | char *test_tmBdry_sizeFunction(); 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /src/tmesh/test/unit_tests.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tmesh/minunit.h" 3 | #include "tmesh/dbg.h" 4 | #include "tmesh_tests.h" 5 | #include "tmList_tests.h" 6 | #include "tmParam_tests.h" 7 | #include "tmesh_cylinder.h" 8 | #include "geom_tests.h" 9 | #include "tmesh_examples.h" 10 | 11 | /************************************************************ 12 | * Run all unit test functions 13 | ************************************************************/ 14 | char *all_tests() 15 | { 16 | mu_suite_start(); 17 | 18 | /********************************************************** 19 | * Unit tests for list structure 20 | ********************************************************** 21 | mu_run_test(test_tmList_create); 22 | mu_run_test(test_tmList_push_pop); 23 | mu_run_test(test_tmList_unshift); 24 | mu_run_test(test_tmList_remove); 25 | mu_run_test(test_tmList_shift); 26 | mu_run_test(test_tmList_join); 27 | mu_run_test(test_tmList_destroy); 28 | mu_run_test(test_tmList_split);*/ 29 | 30 | /********************************************************** 31 | * Unit tests for parameter file reader 32 | **********************************************************/ 33 | //mu_run_test(test_tmParam_readfile); 34 | mu_run_test(test_tmParam_comments); 35 | 36 | /********************************************************** 37 | * Unit tests for tmesh library 38 | **********************************************************/ 39 | //mu_run_test(test_geometric_functions); 40 | //mu_run_test(test_tmTri_intersection); 41 | //mu_run_test(test_mesh_create_destroy); 42 | //mu_run_test(test_tmMesh_objInside); 43 | //mu_run_test(test_tmQtree); 44 | //mu_run_test(test_tmQtree_2); 45 | //mu_run_test(test_tmQtree_performance); 46 | //mu_run_test(test_tmQtree_performance2); 47 | //mu_run_test(test_tmBdry_refine); 48 | //mu_run_test(test_tmFront_init); 49 | //mu_run_test(test_tmFront_advance); 50 | //mu_run_test(test_tmFront_simpleMesh); 51 | //mu_run_test(test_tmFront_simpleMesh2); 52 | //mu_run_test(test_tmFront_innerOuterMesh); 53 | //mu_run_test(test_tmFront_tMesh); 54 | //mu_run_test(test_tmQuad_transformation); 55 | 56 | //mu_run_test(test_tmBdry_sizeFunction); 57 | 58 | //mu_run_test(test_mesh_cylinder); 59 | 60 | 61 | /********************************************************** 62 | * TMesh Examples 63 | **********************************************************/ 64 | //mu_run_test(test_example_1); 65 | //mu_run_test(test_example_2); 66 | 67 | 68 | return NULL; 69 | } 70 | 71 | 72 | /************************************************************ 73 | * Main function to run unit tests 74 | ************************************************************/ 75 | int main(int argc, char *argv[]) 76 | { 77 | debug("----- RUNNING %s\n", argv[0]); 78 | 79 | char *result; 80 | result = all_tests(); 81 | 82 | if (result != 0) 83 | { 84 | debug("FAILED: %s\n", result); 85 | } 86 | else 87 | { 88 | debug("\nALL TESTS PASSED!\n"); 89 | } 90 | 91 | mu_print_tests_run(); 92 | 93 | exit(result != 0); 94 | } 95 | --------------------------------------------------------------------------------