SVG2mesh 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- svg2mesh-1.0.0/LICENSE +21 -0
- svg2mesh-1.0.0/PKG-INFO +158 -0
- svg2mesh-1.0.0/README.md +115 -0
- svg2mesh-1.0.0/SVG2mesh.egg-info/PKG-INFO +158 -0
- svg2mesh-1.0.0/SVG2mesh.egg-info/SOURCES.txt +10 -0
- svg2mesh-1.0.0/SVG2mesh.egg-info/dependency_links.txt +1 -0
- svg2mesh-1.0.0/SVG2mesh.egg-info/entry_points.txt +2 -0
- svg2mesh-1.0.0/SVG2mesh.egg-info/requires.txt +4 -0
- svg2mesh-1.0.0/SVG2mesh.egg-info/top_level.txt +1 -0
- svg2mesh-1.0.0/pyproject.toml +27 -0
- svg2mesh-1.0.0/setup.cfg +4 -0
- svg2mesh-1.0.0/svg2mesh/svg2mesh.py +373 -0
svg2mesh-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 SVG2mesh developers
|
|
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.
|
svg2mesh-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: SVG2mesh
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: FE mesh generator
|
|
5
|
+
Author-email: Vladimír Lukeš <vlukes@fav.zcu.cz>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 SVG2mesh developers
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: homepage, https://github.com/sfepy/svg2mesh
|
|
29
|
+
Keywords: SVG,FE mesh,generator
|
|
30
|
+
Classifier: Development Status :: 4 - Beta
|
|
31
|
+
Classifier: Intended Audience :: Developers
|
|
32
|
+
Classifier: Topic :: Scientific/Engineering
|
|
33
|
+
Classifier: Programming Language :: Python
|
|
34
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
35
|
+
Requires-Python: >=3.8
|
|
36
|
+
Description-Content-Type: text/markdown
|
|
37
|
+
License-File: LICENSE
|
|
38
|
+
Requires-Dist: numpy
|
|
39
|
+
Requires-Dist: gmsh
|
|
40
|
+
Requires-Dist: meshio
|
|
41
|
+
Requires-Dist: svgelements
|
|
42
|
+
Dynamic: license-file
|
|
43
|
+
|
|
44
|
+
# SVG2mesh
|
|
45
|
+
|
|
46
|
+
Generate finite element meshes from SVG-defined geometry.
|
|
47
|
+
|
|
48
|
+
SVG2mesh converts 2D geometries stored in SVG files into finite element meshes
|
|
49
|
+
using Gmsh. The generated mesh can be exported to formats supported by MeshIO
|
|
50
|
+
and used in finite element analysis and scientific computing workflows.
|
|
51
|
+
|
|
52
|
+
## Features
|
|
53
|
+
|
|
54
|
+
- Create FE meshes directly from SVG geometry
|
|
55
|
+
- Mesh generation powered by Gmsh
|
|
56
|
+
- Export meshes through MeshIO
|
|
57
|
+
- Optional generation of periodic meshes
|
|
58
|
+
- Export geometry preview as PNG
|
|
59
|
+
|
|
60
|
+
## Installation
|
|
61
|
+
|
|
62
|
+
### Requirements
|
|
63
|
+
|
|
64
|
+
- Python 3.8+
|
|
65
|
+
- NumPy
|
|
66
|
+
- Gmsh
|
|
67
|
+
- MeshIO
|
|
68
|
+
- svgelements
|
|
69
|
+
|
|
70
|
+
### Install from Source
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
git clone https://github.com/sfepy/svg2mesh.git
|
|
74
|
+
cd svg2mesh
|
|
75
|
+
pip install .
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Install form PyPI
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
pip install svg2mesh
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Usage
|
|
85
|
+
|
|
86
|
+
### Basic Usage
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
svg2mesh geometry.svg
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Specify Output File
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
svg2mesh geometry.svg -o mesh.vtk
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Generate Unit Cell Mesh
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
svg2mesh geometry.svg -u
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Generate Periodic Mesh
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
svg2mesh geometry.svg -p
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Control Mesh Size
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
svg2mesh geometry.svg -s 0.05
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Export PNG Preview
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
svg2mesh geometry.svg -e
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Input Geometry
|
|
123
|
+
|
|
124
|
+
The input geometry must be provided as a **plain** SVG file.
|
|
125
|
+
|
|
126
|
+
Each physical (material) group must be defined in a separate SVG group labeled `layer1`, `layer2`, `layer3`, and so on. These layers are used to identify individual material regions in the generated mesh.
|
|
127
|
+
|
|
128
|
+
All SVG objects should be defined as paths.
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
## Examples
|
|
132
|
+
|
|
133
|
+
### Mesh1 -- multimaterial part
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
svg2mesh mesh1.svg -s 10
|
|
137
|
+
```
|
|
138
|
+

|
|
139
|
+
|
|
140
|
+
### Mesh2 -- single material part
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
svg2mesh mesh2.svg -s 5
|
|
144
|
+
```
|
|
145
|
+

|
|
146
|
+
|
|
147
|
+
### Mesh3 -- periodic unit cell
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
svg2mesh mesh3.svg -u -s "[10, 2]"
|
|
151
|
+
```
|
|
152
|
+

|
|
153
|
+
|
|
154
|
+
## License
|
|
155
|
+
|
|
156
|
+
SVG2mesh is distributed under the MIT License.
|
|
157
|
+
|
|
158
|
+
See the `LICENSE` file for details.
|
svg2mesh-1.0.0/README.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# SVG2mesh
|
|
2
|
+
|
|
3
|
+
Generate finite element meshes from SVG-defined geometry.
|
|
4
|
+
|
|
5
|
+
SVG2mesh converts 2D geometries stored in SVG files into finite element meshes
|
|
6
|
+
using Gmsh. The generated mesh can be exported to formats supported by MeshIO
|
|
7
|
+
and used in finite element analysis and scientific computing workflows.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- Create FE meshes directly from SVG geometry
|
|
12
|
+
- Mesh generation powered by Gmsh
|
|
13
|
+
- Export meshes through MeshIO
|
|
14
|
+
- Optional generation of periodic meshes
|
|
15
|
+
- Export geometry preview as PNG
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
### Requirements
|
|
20
|
+
|
|
21
|
+
- Python 3.8+
|
|
22
|
+
- NumPy
|
|
23
|
+
- Gmsh
|
|
24
|
+
- MeshIO
|
|
25
|
+
- svgelements
|
|
26
|
+
|
|
27
|
+
### Install from Source
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
git clone https://github.com/sfepy/svg2mesh.git
|
|
31
|
+
cd svg2mesh
|
|
32
|
+
pip install .
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Install form PyPI
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install svg2mesh
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
### Basic Usage
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
svg2mesh geometry.svg
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Specify Output File
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
svg2mesh geometry.svg -o mesh.vtk
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Generate Unit Cell Mesh
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
svg2mesh geometry.svg -u
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Generate Periodic Mesh
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
svg2mesh geometry.svg -p
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Control Mesh Size
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
svg2mesh geometry.svg -s 0.05
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Export PNG Preview
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
svg2mesh geometry.svg -e
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Input Geometry
|
|
80
|
+
|
|
81
|
+
The input geometry must be provided as a **plain** SVG file.
|
|
82
|
+
|
|
83
|
+
Each physical (material) group must be defined in a separate SVG group labeled `layer1`, `layer2`, `layer3`, and so on. These layers are used to identify individual material regions in the generated mesh.
|
|
84
|
+
|
|
85
|
+
All SVG objects should be defined as paths.
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
## Examples
|
|
89
|
+
|
|
90
|
+
### Mesh1 -- multimaterial part
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
svg2mesh mesh1.svg -s 10
|
|
94
|
+
```
|
|
95
|
+

|
|
96
|
+
|
|
97
|
+
### Mesh2 -- single material part
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
svg2mesh mesh2.svg -s 5
|
|
101
|
+
```
|
|
102
|
+

|
|
103
|
+
|
|
104
|
+
### Mesh3 -- periodic unit cell
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
svg2mesh mesh3.svg -u -s "[10, 2]"
|
|
108
|
+
```
|
|
109
|
+

|
|
110
|
+
|
|
111
|
+
## License
|
|
112
|
+
|
|
113
|
+
SVG2mesh is distributed under the MIT License.
|
|
114
|
+
|
|
115
|
+
See the `LICENSE` file for details.
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: SVG2mesh
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: FE mesh generator
|
|
5
|
+
Author-email: Vladimír Lukeš <vlukes@fav.zcu.cz>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 SVG2mesh developers
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: homepage, https://github.com/sfepy/svg2mesh
|
|
29
|
+
Keywords: SVG,FE mesh,generator
|
|
30
|
+
Classifier: Development Status :: 4 - Beta
|
|
31
|
+
Classifier: Intended Audience :: Developers
|
|
32
|
+
Classifier: Topic :: Scientific/Engineering
|
|
33
|
+
Classifier: Programming Language :: Python
|
|
34
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
35
|
+
Requires-Python: >=3.8
|
|
36
|
+
Description-Content-Type: text/markdown
|
|
37
|
+
License-File: LICENSE
|
|
38
|
+
Requires-Dist: numpy
|
|
39
|
+
Requires-Dist: gmsh
|
|
40
|
+
Requires-Dist: meshio
|
|
41
|
+
Requires-Dist: svgelements
|
|
42
|
+
Dynamic: license-file
|
|
43
|
+
|
|
44
|
+
# SVG2mesh
|
|
45
|
+
|
|
46
|
+
Generate finite element meshes from SVG-defined geometry.
|
|
47
|
+
|
|
48
|
+
SVG2mesh converts 2D geometries stored in SVG files into finite element meshes
|
|
49
|
+
using Gmsh. The generated mesh can be exported to formats supported by MeshIO
|
|
50
|
+
and used in finite element analysis and scientific computing workflows.
|
|
51
|
+
|
|
52
|
+
## Features
|
|
53
|
+
|
|
54
|
+
- Create FE meshes directly from SVG geometry
|
|
55
|
+
- Mesh generation powered by Gmsh
|
|
56
|
+
- Export meshes through MeshIO
|
|
57
|
+
- Optional generation of periodic meshes
|
|
58
|
+
- Export geometry preview as PNG
|
|
59
|
+
|
|
60
|
+
## Installation
|
|
61
|
+
|
|
62
|
+
### Requirements
|
|
63
|
+
|
|
64
|
+
- Python 3.8+
|
|
65
|
+
- NumPy
|
|
66
|
+
- Gmsh
|
|
67
|
+
- MeshIO
|
|
68
|
+
- svgelements
|
|
69
|
+
|
|
70
|
+
### Install from Source
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
git clone https://github.com/sfepy/svg2mesh.git
|
|
74
|
+
cd svg2mesh
|
|
75
|
+
pip install .
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Install form PyPI
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
pip install svg2mesh
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Usage
|
|
85
|
+
|
|
86
|
+
### Basic Usage
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
svg2mesh geometry.svg
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Specify Output File
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
svg2mesh geometry.svg -o mesh.vtk
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Generate Unit Cell Mesh
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
svg2mesh geometry.svg -u
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Generate Periodic Mesh
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
svg2mesh geometry.svg -p
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Control Mesh Size
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
svg2mesh geometry.svg -s 0.05
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Export PNG Preview
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
svg2mesh geometry.svg -e
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Input Geometry
|
|
123
|
+
|
|
124
|
+
The input geometry must be provided as a **plain** SVG file.
|
|
125
|
+
|
|
126
|
+
Each physical (material) group must be defined in a separate SVG group labeled `layer1`, `layer2`, `layer3`, and so on. These layers are used to identify individual material regions in the generated mesh.
|
|
127
|
+
|
|
128
|
+
All SVG objects should be defined as paths.
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
## Examples
|
|
132
|
+
|
|
133
|
+
### Mesh1 -- multimaterial part
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
svg2mesh mesh1.svg -s 10
|
|
137
|
+
```
|
|
138
|
+

|
|
139
|
+
|
|
140
|
+
### Mesh2 -- single material part
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
svg2mesh mesh2.svg -s 5
|
|
144
|
+
```
|
|
145
|
+

|
|
146
|
+
|
|
147
|
+
### Mesh3 -- periodic unit cell
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
svg2mesh mesh3.svg -u -s "[10, 2]"
|
|
151
|
+
```
|
|
152
|
+

|
|
153
|
+
|
|
154
|
+
## License
|
|
155
|
+
|
|
156
|
+
SVG2mesh is distributed under the MIT License.
|
|
157
|
+
|
|
158
|
+
See the `LICENSE` file for details.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
SVG2mesh.egg-info/PKG-INFO
|
|
5
|
+
SVG2mesh.egg-info/SOURCES.txt
|
|
6
|
+
SVG2mesh.egg-info/dependency_links.txt
|
|
7
|
+
SVG2mesh.egg-info/entry_points.txt
|
|
8
|
+
SVG2mesh.egg-info/requires.txt
|
|
9
|
+
SVG2mesh.egg-info/top_level.txt
|
|
10
|
+
svg2mesh/svg2mesh.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
svg2mesh
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project.urls]
|
|
6
|
+
homepage = "https://github.com/sfepy/svg2mesh"
|
|
7
|
+
|
|
8
|
+
[project.scripts]
|
|
9
|
+
svg2mesh = "svg2mesh.svg2mesh:main"
|
|
10
|
+
|
|
11
|
+
[project]
|
|
12
|
+
name = "SVG2mesh"
|
|
13
|
+
version = "1.0.0"
|
|
14
|
+
readme = "README.md"
|
|
15
|
+
description="FE mesh generator "
|
|
16
|
+
license = {file = "LICENSE"}
|
|
17
|
+
authors = [{name = "Vladimír Lukeš", email = "vlukes@fav.zcu.cz"}]
|
|
18
|
+
requires-python = ">=3.8"
|
|
19
|
+
dependencies = ["numpy", "gmsh", "meshio", "svgelements"]
|
|
20
|
+
keywords = ["SVG", "FE mesh", "generator"]
|
|
21
|
+
classifiers = [
|
|
22
|
+
"Development Status :: 4 - Beta", # 3 - Alpha, 4 - Beta, 5 - Stable
|
|
23
|
+
"Intended Audience :: Developers",
|
|
24
|
+
"Topic :: Scientific/Engineering",
|
|
25
|
+
"Programming Language :: Python",
|
|
26
|
+
"License :: OSI Approved :: MIT License",
|
|
27
|
+
]
|
svg2mesh-1.0.0/setup.cfg
ADDED
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import os
|
|
3
|
+
import argparse
|
|
4
|
+
from ast import literal_eval
|
|
5
|
+
import numpy as nm
|
|
6
|
+
import gmsh
|
|
7
|
+
import meshio
|
|
8
|
+
from svgelements import SVG
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def set_periodic(model, dx, dy, dz=0, dim=2):
|
|
12
|
+
"""
|
|
13
|
+
Set mesh periodic.
|
|
14
|
+
|
|
15
|
+
Inputs
|
|
16
|
+
======
|
|
17
|
+
model: gmsh.model
|
|
18
|
+
GMSH model
|
|
19
|
+
dx, dy, dz: floats
|
|
20
|
+
Domain dimensions
|
|
21
|
+
"""
|
|
22
|
+
def set_periodic(master, slave, dx, dy, dz):
|
|
23
|
+
for m, s in zip(master, slave):
|
|
24
|
+
gmsh.model.mesh.setPeriodic(
|
|
25
|
+
dim - 1, [s], [m],
|
|
26
|
+
[1, 0, 0, dx,
|
|
27
|
+
0, 1, 0, dy,
|
|
28
|
+
0, 0, 1, dz,
|
|
29
|
+
0, 0, 0, 1]
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
tol = 1e-6
|
|
33
|
+
bnd = nm.array([(tag,) + tuple(gmsh.model.occ.getCenterOfMass(d, tag))
|
|
34
|
+
for d, tag in model.getEntities(dim=dim-1)])
|
|
35
|
+
|
|
36
|
+
for k in range(dim):
|
|
37
|
+
cmin, cmax = nm.min(bnd[:, k + 1]), nm.max(bnd[:, k + 1])
|
|
38
|
+
midxs = nm.where(nm.abs(bnd[:, k + 1] - cmin) < tol)[0]
|
|
39
|
+
sidxs = nm.where(nm.abs(bnd[:, k + 1] - cmax) < tol)[0]
|
|
40
|
+
|
|
41
|
+
dv = nm.array([0] * 3)
|
|
42
|
+
dd = cmax - cmin
|
|
43
|
+
dv[k] = dd
|
|
44
|
+
|
|
45
|
+
pairs = []
|
|
46
|
+
for m in midxs:
|
|
47
|
+
dist = nm.linalg.norm(bnd[sidxs, 1:] - dv - bnd[m, 1:], axis=1)
|
|
48
|
+
idx = nm.where(dist < (dd * tol))[0]
|
|
49
|
+
pairs.append((m, sidxs[idx[0]]))
|
|
50
|
+
|
|
51
|
+
pairs = nm.array(pairs)
|
|
52
|
+
args = tuple(bnd[pairs, 0].T) + tuple(dv)
|
|
53
|
+
set_periodic(*args)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def set_mesh_size(model, pgroups, msize, dim=2):
|
|
57
|
+
"""
|
|
58
|
+
Set mesh size individually to each physical group.
|
|
59
|
+
|
|
60
|
+
Inputs
|
|
61
|
+
======
|
|
62
|
+
model: gmsh.model
|
|
63
|
+
GMSH model
|
|
64
|
+
pgroups: list
|
|
65
|
+
Physical group IDs
|
|
66
|
+
msize: list of floats
|
|
67
|
+
Mesh size for each physical group
|
|
68
|
+
"""
|
|
69
|
+
mesh = model.mesh
|
|
70
|
+
fields = []
|
|
71
|
+
for pg, ms in zip(pgroups, msize):
|
|
72
|
+
entities = model.getEntitiesForPhysicalGroup(dim, pg)
|
|
73
|
+
field = mesh.field.add("Constant")
|
|
74
|
+
mesh.field.setNumbers(field, "SurfacesList", entities)
|
|
75
|
+
mesh.field.setNumber(field, "VIn", ms)
|
|
76
|
+
fields.append(field)
|
|
77
|
+
|
|
78
|
+
field = mesh.field.add("Min")
|
|
79
|
+
mesh.field.setNumbers(field, "FieldsList", fields)
|
|
80
|
+
mesh.field.setAsBackgroundMesh(field)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def gmsh_init():
|
|
84
|
+
"Initiate GMSH module."
|
|
85
|
+
gmsh.initialize()
|
|
86
|
+
gmsh.logger.start()
|
|
87
|
+
gmsh.model.add('boolean')
|
|
88
|
+
|
|
89
|
+
return gmsh, gmsh.model, gmsh.model.occ
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def get_xy(p, dec=6):
|
|
93
|
+
return (float(nm.round(p.x, dec)), float(nm.round(p.y, dec)))
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def quadratic_to_cubic(p0, c1, p1):
|
|
97
|
+
"Convert SVG quadratic bezier into equivalent cubic bezier."
|
|
98
|
+
|
|
99
|
+
c1 = (p0[0] + 2.0/3.0*(c1[0] - p0[0]),
|
|
100
|
+
p0[1] + 2.0/3.0*(c1[1] - p0[1]))
|
|
101
|
+
c2 = (p1[0] + 2.0/3.0*(c1[0] - p1[0]),
|
|
102
|
+
p1[1] + 2.0/3.0*(c1[1] - p1[1]))
|
|
103
|
+
|
|
104
|
+
return c1, c2
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def rotate_obj(obj, angle, occ, h, cx=0, cy=0):
|
|
108
|
+
"Rotate OCC object around Z axis."
|
|
109
|
+
if nm.abs(angle) > 1e-3:
|
|
110
|
+
occ.rotate([obj], cx, h - cy, 0, 0, 0, 1, angle)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def get_layer_elements(elements, occ, cargs, merge=False, oflag=''):
|
|
114
|
+
out = []
|
|
115
|
+
for el in elements:
|
|
116
|
+
if isinstance(el, list):
|
|
117
|
+
out += get_layer_elements(el, occ, cargs, True, ' ')
|
|
118
|
+
else:
|
|
119
|
+
shape = el.__class__.__name__
|
|
120
|
+
print(f'{oflag}{shape}: {el}')
|
|
121
|
+
if shape == 'Rect':
|
|
122
|
+
y = cargs[4] - el.y - el.height
|
|
123
|
+
out.append((2, occ.addRectangle(el.x, y, 0,
|
|
124
|
+
el.width, el.height)))
|
|
125
|
+
# rotate_obj(out[-1], -el.rotation, occ, cargs[4])
|
|
126
|
+
# el.transform[4], el.transform[5])
|
|
127
|
+
|
|
128
|
+
elif shape == 'Ellipse':
|
|
129
|
+
out.append((2, occ.addDisk(el.cx, cargs[4] - el.cy, 0,
|
|
130
|
+
el.rx, el.ry)))
|
|
131
|
+
rotate_obj(out[-1], -el.rotation, occ, cargs[4])
|
|
132
|
+
|
|
133
|
+
elif shape == 'Path':
|
|
134
|
+
point_keys = {get_xy(p) for p in el.as_points()}
|
|
135
|
+
points = {p: occ.addPoint(p[0], cargs[4] - p[1], 0)
|
|
136
|
+
for p in point_keys}
|
|
137
|
+
|
|
138
|
+
loops, lines = [], []
|
|
139
|
+
for seg in el:
|
|
140
|
+
seg_name = seg.__class__.__name__
|
|
141
|
+
if seg_name == 'Move':
|
|
142
|
+
if len(lines) > 0:
|
|
143
|
+
if el.id.startswith('text'):
|
|
144
|
+
loops.append(occ.addCurveLoop(lines))
|
|
145
|
+
out.append((2, occ.addPlaneSurface(loops)))
|
|
146
|
+
else:
|
|
147
|
+
loops.append(occ.addCurveLoop(lines))
|
|
148
|
+
lines = []
|
|
149
|
+
|
|
150
|
+
elif seg_name in ['Line', 'Close']:
|
|
151
|
+
p1, p2 = get_xy(seg.start), get_xy(seg.end)
|
|
152
|
+
if p1 != p2:
|
|
153
|
+
lines.append(occ.addLine(points[p1], points[p2]))
|
|
154
|
+
|
|
155
|
+
elif seg_name == 'QuadraticBezier':
|
|
156
|
+
p1, c12, p2 = (get_xy(seg.start), get_xy(seg.control),
|
|
157
|
+
get_xy(seg.end))
|
|
158
|
+
c1, c2 = quadratic_to_cubic(p1, c12, p2)
|
|
159
|
+
points[c1] = occ.addPoint(c1[0], cargs[4] - c1[1], 0)
|
|
160
|
+
points[c2] = occ.addPoint(c2[0], cargs[4] - c2[1], 0)
|
|
161
|
+
lines.append(occ.addBezier([points[p1], points[c1],
|
|
162
|
+
points[c2], points[p2]]))
|
|
163
|
+
|
|
164
|
+
elif seg_name == 'CubicBezier':
|
|
165
|
+
p1, p2 = get_xy(seg.start), get_xy(seg.end)
|
|
166
|
+
c1, c2 = get_xy(seg.control1), get_xy(seg.control2)
|
|
167
|
+
lines.append(occ.addBezier([points[p1], points[c1],
|
|
168
|
+
points[c2], points[p2]]))
|
|
169
|
+
|
|
170
|
+
elif seg_name == 'Arc':
|
|
171
|
+
apoints = [get_xy(seg.point(t))
|
|
172
|
+
for t in nm.linspace(0, 1, 30)]
|
|
173
|
+
spoints = []
|
|
174
|
+
for apt in apoints:
|
|
175
|
+
if apt not in points:
|
|
176
|
+
y = cargs[4] - apt[1]
|
|
177
|
+
points[apt] = occ.addPoint(apt[0], y, 0)
|
|
178
|
+
spoints.append(points[apt])
|
|
179
|
+
|
|
180
|
+
lines.append(occ.addBSpline(spoints))
|
|
181
|
+
|
|
182
|
+
else:
|
|
183
|
+
raise ValueError(f'Unknown Path element "{seg_name}"!')
|
|
184
|
+
|
|
185
|
+
loops.append(occ.addCurveLoop(lines))
|
|
186
|
+
out.append((2, occ.addPlaneSurface(loops)))
|
|
187
|
+
|
|
188
|
+
else:
|
|
189
|
+
raise ValueError(f'Unknown SVG element "{shape}"!')
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
# merge grouped objects
|
|
193
|
+
if merge and len(out) > 1:
|
|
194
|
+
out, _ = occ.fuse(out[:1], out[1:])
|
|
195
|
+
|
|
196
|
+
# crop to view box
|
|
197
|
+
if cargs and len(out) > 0:
|
|
198
|
+
cbox1 = (2, occ.addRectangle(*cargs))
|
|
199
|
+
cbox2 = (2, occ.addRectangle(-cargs[3], -cargs[4], cargs[2],
|
|
200
|
+
3*cargs[3], 3*cargs[4]))
|
|
201
|
+
cbox, _ = occ.cut([cbox2], [cbox1])
|
|
202
|
+
out, _ = occ.cut(out, cbox)
|
|
203
|
+
|
|
204
|
+
return out
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def save_png(filename_out, filename_png):
|
|
208
|
+
"""
|
|
209
|
+
Save mesh screenshot as PNG file.
|
|
210
|
+
|
|
211
|
+
Inputs
|
|
212
|
+
======
|
|
213
|
+
filename_out: str
|
|
214
|
+
Output file name
|
|
215
|
+
filename_png: str
|
|
216
|
+
PNG output file name
|
|
217
|
+
"""
|
|
218
|
+
import pyvista as pv
|
|
219
|
+
|
|
220
|
+
mesh = meshio.read(filename_out)
|
|
221
|
+
|
|
222
|
+
plotter = pv.Plotter(off_screen=True)
|
|
223
|
+
plotter.add_mesh(mesh, show_edges=True, scalars='mat_id', show_scalar_bar=False)
|
|
224
|
+
|
|
225
|
+
plotter.view_xy()
|
|
226
|
+
plotter.camera.zoom(1.4)
|
|
227
|
+
plotter.image_scale = 2
|
|
228
|
+
plotter.show(screenshot=filename_png)
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def sum_dict(d):
|
|
232
|
+
return sum(d, [])
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def gen_mesh_from_svg(filename_svg, filename_out=None,
|
|
236
|
+
mesh_size=None, unit_cell=False,
|
|
237
|
+
periodic=False, export_png=False):
|
|
238
|
+
"""
|
|
239
|
+
Generate FE mesh from geometry defined by a SVG file.
|
|
240
|
+
|
|
241
|
+
Inputs
|
|
242
|
+
======
|
|
243
|
+
filename_svg: str
|
|
244
|
+
SVG file name
|
|
245
|
+
filename_out: str
|
|
246
|
+
Output file name
|
|
247
|
+
mesh_size: float
|
|
248
|
+
Size of mesh elements
|
|
249
|
+
unit_cell: bool
|
|
250
|
+
If True, generate periodic unit cell
|
|
251
|
+
periodic: bool
|
|
252
|
+
If True, generate periodic mesh
|
|
253
|
+
export_png: bool
|
|
254
|
+
If True, save mesh screenshot (PNG)
|
|
255
|
+
"""
|
|
256
|
+
gmsh, model, occ = gmsh_init()
|
|
257
|
+
|
|
258
|
+
# set ppi=25.4 to keep units in mm
|
|
259
|
+
svg = SVG.parse(filename_svg, ppi=25.4)
|
|
260
|
+
|
|
261
|
+
vbox = svg.viewbox
|
|
262
|
+
cargs = (vbox.x, vbox.y, 0, vbox.width, vbox.height)
|
|
263
|
+
|
|
264
|
+
layers = []
|
|
265
|
+
layer_ids = []
|
|
266
|
+
for el in svg:
|
|
267
|
+
lid = int(el.id.replace('layer', ''))
|
|
268
|
+
print(f'layer {lid}:')
|
|
269
|
+
layers.append(get_layer_elements(el, occ, cargs, oflag=' '))
|
|
270
|
+
layer_ids.append(lid)
|
|
271
|
+
|
|
272
|
+
if len(layers) > 1:
|
|
273
|
+
_, ovv = occ.fragment(layers[0], sum_dict(layers[1:]))
|
|
274
|
+
else:
|
|
275
|
+
ovv = layers
|
|
276
|
+
|
|
277
|
+
model.occ.synchronize()
|
|
278
|
+
|
|
279
|
+
mids = sum_dict([[ik] * len(k) for ik, k in enumerate(layers)])
|
|
280
|
+
tags_1 = set()
|
|
281
|
+
pgs = [[] for _ in range(len(layers))]
|
|
282
|
+
for mid in nm.arange(len(ovv))[::-1]:
|
|
283
|
+
ids = [k for _, k in ovv[mid] if k not in tags_1]
|
|
284
|
+
tags_1 = tags_1 | set(ids)
|
|
285
|
+
pgs[mids[mid]].append(ids)
|
|
286
|
+
|
|
287
|
+
pgs1 = []
|
|
288
|
+
for mid, pg in enumerate(pgs):
|
|
289
|
+
pgs1.append(model.addPhysicalGroup(2, sum_dict(pg), layer_ids[mid]))
|
|
290
|
+
|
|
291
|
+
if mesh_size is None:
|
|
292
|
+
mesh_size = vbox.width / 10
|
|
293
|
+
|
|
294
|
+
if isinstance(mesh_size, (int, float)):
|
|
295
|
+
ms = [mesh_size] * len(pgs1)
|
|
296
|
+
else:
|
|
297
|
+
ms = mesh_size
|
|
298
|
+
|
|
299
|
+
if periodic or unit_cell:
|
|
300
|
+
set_periodic(model, vbox.width, vbox.height, 0)
|
|
301
|
+
|
|
302
|
+
set_mesh_size(model, pgs1, ms)
|
|
303
|
+
gmsh.option.setNumber("Mesh.Algorithm", 2)
|
|
304
|
+
|
|
305
|
+
model.mesh.generate(2)
|
|
306
|
+
|
|
307
|
+
filename_base = os.path.splitext(filename_svg)[0]
|
|
308
|
+
filename_msh = f'{filename_base}.msh'
|
|
309
|
+
|
|
310
|
+
gmsh.write(filename_msh)
|
|
311
|
+
gmsh.finalize()
|
|
312
|
+
|
|
313
|
+
mesh = meshio.read(filename_msh)
|
|
314
|
+
mesh.cell_data = {'mat_id': mesh.cell_data['gmsh:physical']}
|
|
315
|
+
mesh.point_data = {}
|
|
316
|
+
mesh.cell_sets = None
|
|
317
|
+
|
|
318
|
+
if unit_cell:
|
|
319
|
+
points = mesh.points
|
|
320
|
+
bbox = [nm.min(points, axis=0), nm.max(points, axis=0)]
|
|
321
|
+
points -= bbox[0]
|
|
322
|
+
dd = bbox[1] - bbox[0]
|
|
323
|
+
for k, d in enumerate(dd[:2]):
|
|
324
|
+
points[:, k] /= d
|
|
325
|
+
points[nm.abs(points[:, k]) < 1e-6, k] = 0.
|
|
326
|
+
|
|
327
|
+
print(mesh)
|
|
328
|
+
|
|
329
|
+
if filename_out is None:
|
|
330
|
+
filename_out = f'{filename_base}.vtk'
|
|
331
|
+
|
|
332
|
+
mesh.write(filename_out, binary=False)
|
|
333
|
+
|
|
334
|
+
if export_png:
|
|
335
|
+
filename_png = f'{filename_base}.png'
|
|
336
|
+
save_png(filename_out, filename_png)
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
def parse_args():
|
|
340
|
+
parser = argparse.ArgumentParser(
|
|
341
|
+
prog='SVG2MESH',
|
|
342
|
+
description='SVG2MESH - Generate FE mesh using SVG defined geometry.')
|
|
343
|
+
|
|
344
|
+
parser.add_argument('filename_svg')
|
|
345
|
+
parser.add_argument('-o', '--output', action='store',
|
|
346
|
+
dest='filename_out', default=None)
|
|
347
|
+
parser.add_argument('-u', '--unit-cell', action='store_true',
|
|
348
|
+
dest='unit_cell', default=False)
|
|
349
|
+
parser.add_argument('-p', '--periodic', action='store_true',
|
|
350
|
+
dest='periodic', default=False)
|
|
351
|
+
parser.add_argument('-s', '--mesh-size', action='store',
|
|
352
|
+
dest='mesh_size', default=None)
|
|
353
|
+
parser.add_argument('-e', '--export-png', action='store_true',
|
|
354
|
+
dest='export_png', default=False)
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
return parser.parse_args()
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def main():
|
|
361
|
+
args = parse_args()
|
|
362
|
+
|
|
363
|
+
mesh_size = args.mesh_size
|
|
364
|
+
if mesh_size is not None:
|
|
365
|
+
mesh_size = literal_eval(mesh_size)
|
|
366
|
+
|
|
367
|
+
gen_mesh_from_svg(args.filename_svg, filename_out=args.filename_out,
|
|
368
|
+
mesh_size=mesh_size, unit_cell=args.unit_cell,
|
|
369
|
+
periodic=args.periodic, export_png=args.export_png)
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
if __name__ == '__main__':
|
|
373
|
+
main()
|