emerge 0.6.5__tar.gz → 0.6.7__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.
Potentially problematic release.
This version of emerge might be problematic. Click here for more details.
- {emerge-0.6.5 → emerge-0.6.7}/.bumpversion.toml +1 -1
- {emerge-0.6.5 → emerge-0.6.7}/PKG-INFO +1 -1
- {emerge-0.6.5 → emerge-0.6.7}/emerge/__init__.py +2 -1
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/geo/__init__.py +1 -1
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/geo/operations.py +97 -23
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/geo/pcb.py +54 -14
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/geo/shapes.py +101 -30
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/geometry.py +45 -14
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/howto.py +1 -1
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/physics/microwave/microwave_bc.py +2 -4
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/physics/microwave/microwave_data.py +13 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/plot/pyvista/display.py +113 -15
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/selection.py +1 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/simmodel.py +10 -8
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/solver.py +4 -4
- {emerge-0.6.5 → emerge-0.6.7}/examples/demo10_sgh.py +2 -2
- {emerge-0.6.5 → emerge-0.6.7}/examples/demo11_lumped_element_filter.py +2 -2
- {emerge-0.6.5 → emerge-0.6.7}/examples/demo12_mode_alignment.py +1 -1
- {emerge-0.6.5 → emerge-0.6.7}/examples/demo13_helix_antenna.py +3 -3
- {emerge-0.6.5 → emerge-0.6.7}/examples/demo14_boundary_selection.py +2 -2
- {emerge-0.6.5 → emerge-0.6.7}/examples/demo1_stepped_imp_filter.py +2 -2
- {emerge-0.6.5 → emerge-0.6.7}/examples/demo2_combline_filter.py +1 -1
- {emerge-0.6.5 → emerge-0.6.7}/examples/demo3_coupled_line_filter.py +1 -1
- {emerge-0.6.5 → emerge-0.6.7}/examples/demo4_patch_antenna.py +3 -3
- {emerge-0.6.5 → emerge-0.6.7}/examples/demo5_revolve.py +1 -1
- {emerge-0.6.5 → emerge-0.6.7}/examples/demo6_striplines_with_vias.py +4 -4
- {emerge-0.6.5 → emerge-0.6.7}/examples/demo7_periodic_cells.py +1 -1
- {emerge-0.6.5 → emerge-0.6.7}/examples/demo8_waveguide_bpf_synthesis.py +1 -1
- {emerge-0.6.5 → emerge-0.6.7}/examples/demo9_dielectric_resonator.py +1 -1
- {emerge-0.6.5 → emerge-0.6.7}/pyproject.toml +1 -1
- {emerge-0.6.5 → emerge-0.6.7}/uv.lock +1 -1
- {emerge-0.6.5 → emerge-0.6.7}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/.gitignore +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/.opt +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/.python-version +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/LICENSE +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/README.md +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/THIRD_PARTY_LICENSES.md +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/UMFPACK_Install_windows.md +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/UMFPACK_installer_windows.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/__main__.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/__init__.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/_cache_check.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/bc.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/const.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/coord.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/cs.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/dataset.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/elements/__init__.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/elements/femdata.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/elements/index_interp.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/elements/ned2_interp.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/elements/nedelec2.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/elements/nedleg2.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/geo/horn.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/geo/modeler.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/geo/pcb_tools/calculator.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/geo/pcb_tools/macro.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/geo/pmlbox.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/geo/polybased.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/geo/step.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/geo2d.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/logsettings.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/material.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/mesh3d.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/mesher.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/mth/common_functions.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/mth/integrals.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/mth/optimized.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/mth/pairing.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/periodic.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/physics/__init__.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/physics/microwave/__init__.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/physics/microwave/adaptive_freq.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/physics/microwave/assembly/assembler.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/physics/microwave/assembly/curlcurl.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/physics/microwave/assembly/generalized_eigen.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/physics/microwave/assembly/generalized_eigen_hb.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/physics/microwave/assembly/periodicbc.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/physics/microwave/assembly/robinbc.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/physics/microwave/microwave_3d.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/physics/microwave/periodic.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/physics/microwave/port_functions.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/physics/microwave/sc.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/physics/microwave/simjob.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/physics/microwave/sparam.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/physics/microwave/touchstone.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/plot/__init__.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/plot/display.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/plot/matplotlib/mpldisplay.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/plot/pyvista/__init__.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/plot/pyvista/display_settings.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/plot/simple_plots.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/plot.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/projects/__init__.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/projects/_gen_base.txt +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/projects/_load_base.txt +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/projects/generate_project.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/simulation_data.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/solve_interfaces/cudss_interface.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/solve_interfaces/pardiso_interface.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/_emerge/system.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/cli.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/ext.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/lib.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/plot.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/emerge/pyvista.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/src/__init__.py +0 -0
- {emerge-0.6.5 → emerge-0.6.7}/src/_img/logo.jpeg +0 -0
|
@@ -18,7 +18,7 @@ along with this program; if not, see
|
|
|
18
18
|
"""
|
|
19
19
|
import os
|
|
20
20
|
|
|
21
|
-
__version__ = "0.6.
|
|
21
|
+
__version__ = "0.6.7"
|
|
22
22
|
|
|
23
23
|
############################################################
|
|
24
24
|
# HANDLE ENVIRONMENT VARIABLES #
|
|
@@ -52,6 +52,7 @@ from ._emerge.cs import CoordinateSystem, CS, GCS, Plane, Axis, XAX, YAX, ZAX, X
|
|
|
52
52
|
from ._emerge.coord import Line
|
|
53
53
|
from ._emerge import geo
|
|
54
54
|
from ._emerge.selection import Selection, FaceSelection, DomainSelection, EdgeSelection
|
|
55
|
+
from ._emerge.geometry import select
|
|
55
56
|
from ._emerge.mth.common_functions import norm, coax_rout, coax_rin
|
|
56
57
|
from ._emerge.physics.microwave.sc import stratton_chu
|
|
57
58
|
from ._emerge.periodic import RectCell, HexCell
|
|
@@ -19,6 +19,6 @@ from .pcb import PCB
|
|
|
19
19
|
from .pmlbox import pmlbox
|
|
20
20
|
from .horn import Horn
|
|
21
21
|
from .shapes import Cylinder, CoaxCylinder, Box, XYPlate, HalfSphere, Sphere, Plate, OldBox, Alignment, Cone
|
|
22
|
-
from .operations import subtract, add, embed, remove, rotate, mirror, change_coordinate_system, translate, intersect
|
|
22
|
+
from .operations import subtract, add, embed, remove, rotate, mirror, change_coordinate_system, translate, intersect, unite, expand_surface
|
|
23
23
|
from .polybased import XYPolygon, GeoPrism, Disc, Curve
|
|
24
24
|
from .step import STEPItems
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
# along with this program; if not, see
|
|
16
16
|
# <https://www.gnu.org/licenses/>.
|
|
17
17
|
|
|
18
|
-
from typing import TypeVar
|
|
19
|
-
from ..geometry import GeoSurface, GeoVolume, GeoObject, GeoPoint, GeoEdge
|
|
18
|
+
from typing import TypeVar, overload
|
|
19
|
+
from ..geometry import GeoSurface, GeoVolume, GeoObject, GeoPoint, GeoEdge, GeoPolygon
|
|
20
20
|
from ..cs import CoordinateSystem, GCS
|
|
21
21
|
import gmsh
|
|
22
22
|
import numpy as np
|
|
@@ -60,7 +60,7 @@ def add(main: T, tool: T,
|
|
|
60
60
|
main._exists = False
|
|
61
61
|
if remove_tool:
|
|
62
62
|
tool._exists = False
|
|
63
|
-
return output # type: ignore
|
|
63
|
+
return output.set_material(main.material) # type: ignore
|
|
64
64
|
|
|
65
65
|
def remove(main: T, tool: T,
|
|
66
66
|
remove_object: bool = True,
|
|
@@ -90,7 +90,7 @@ def remove(main: T, tool: T,
|
|
|
90
90
|
main._exists = False
|
|
91
91
|
if remove_tool:
|
|
92
92
|
tool._exists = False
|
|
93
|
-
return output # type: ignore
|
|
93
|
+
return output.set_material(main.material) # type: ignore
|
|
94
94
|
|
|
95
95
|
subtract = remove
|
|
96
96
|
|
|
@@ -122,7 +122,7 @@ def intersect(main: T, tool: T,
|
|
|
122
122
|
main._exists = False
|
|
123
123
|
if remove_tool:
|
|
124
124
|
tool._exists = False
|
|
125
|
-
return output #type:ignore
|
|
125
|
+
return output.set_material(main.material) #type:ignore
|
|
126
126
|
|
|
127
127
|
def embed(main: GeoVolume, other: GeoSurface) -> None:
|
|
128
128
|
''' Embeds a surface into a volume in the GMSH model.
|
|
@@ -144,7 +144,8 @@ def rotate(main: GeoVolume,
|
|
|
144
144
|
c0: tuple[float, float, float],
|
|
145
145
|
ax: tuple[float, float, float],
|
|
146
146
|
angle: float,
|
|
147
|
-
|
|
147
|
+
make_copy: bool = False,
|
|
148
|
+
degree=True) -> GeoObject:
|
|
148
149
|
"""Rotates a GeoVolume object around an axist defined at a coordinate.
|
|
149
150
|
|
|
150
151
|
Args:
|
|
@@ -159,17 +160,23 @@ def rotate(main: GeoVolume,
|
|
|
159
160
|
"""
|
|
160
161
|
if degree:
|
|
161
162
|
angle = angle * np.pi/180
|
|
162
|
-
|
|
163
|
-
|
|
163
|
+
|
|
164
|
+
if make_copy:
|
|
165
|
+
rotate_obj = main.make_copy()
|
|
166
|
+
else:
|
|
167
|
+
rotate_obj = main
|
|
168
|
+
|
|
169
|
+
gmsh.model.occ.rotate(rotate_obj.dimtags, *c0, *ax, -angle)
|
|
164
170
|
# Rotate the facepointers
|
|
165
|
-
for fp in
|
|
171
|
+
for fp in rotate_obj._all_pointers:
|
|
166
172
|
fp.rotate(c0, ax, angle)
|
|
167
|
-
return
|
|
173
|
+
return rotate_obj
|
|
168
174
|
|
|
169
175
|
def translate(main: GeoVolume,
|
|
170
176
|
dx: float = 0,
|
|
171
177
|
dy: float = 0,
|
|
172
|
-
dz: float = 0
|
|
178
|
+
dz: float = 0,
|
|
179
|
+
make_copy: bool = False) -> GeoObject:
|
|
173
180
|
"""Translates the GeoVolume object along a given displacement
|
|
174
181
|
|
|
175
182
|
Args:
|
|
@@ -177,17 +184,23 @@ def translate(main: GeoVolume,
|
|
|
177
184
|
dx (float, optional): The X-displacement in meters. Defaults to 0.
|
|
178
185
|
dy (float, optional): The Y-displacement in meters. Defaults to 0.
|
|
179
186
|
dz (float, optional): The Z-displacement in meters. Defaults to 0.
|
|
187
|
+
make_copy (bool, optional): Whether to make a copy first before translating.
|
|
180
188
|
|
|
181
189
|
Returns:
|
|
182
|
-
|
|
190
|
+
GeoObject: The translated object
|
|
183
191
|
"""
|
|
184
|
-
|
|
192
|
+
|
|
193
|
+
if make_copy:
|
|
194
|
+
trans_obj = main.make_copy()
|
|
195
|
+
else:
|
|
196
|
+
trans_obj = main
|
|
197
|
+
gmsh.model.occ.translate(trans_obj.dimtags, dx, dy, dz)
|
|
185
198
|
|
|
186
199
|
# Rotate the facepointers
|
|
187
|
-
for fp in
|
|
200
|
+
for fp in trans_obj._all_pointers:
|
|
188
201
|
fp.translate(dx, dy, dz)
|
|
189
202
|
|
|
190
|
-
return
|
|
203
|
+
return trans_obj
|
|
191
204
|
|
|
192
205
|
def mirror(main: GeoObject,
|
|
193
206
|
origin: tuple[float, float, float] = (0.0, 0.0, 0.0),
|
|
@@ -199,6 +212,7 @@ def mirror(main: GeoObject,
|
|
|
199
212
|
main (GeoVolume): The object to mirror
|
|
200
213
|
origin (tuple[float, float, float], optional): The point of origin in meters. Defaults to (0.0, 0.0, 0.0).
|
|
201
214
|
direction (tuple[float, float, float], optional): The normal axis defining the plane of reflection. Defaults to (1.0, 0.0, 0.0).
|
|
215
|
+
make_copy (bool, optional): Whether to make a copy first before mirroring.
|
|
202
216
|
|
|
203
217
|
Returns:
|
|
204
218
|
GeoVolume: The mirrored GeoVolume object
|
|
@@ -211,14 +225,12 @@ def mirror(main: GeoObject,
|
|
|
211
225
|
d = -(a*x0 + b*y0 + c*z0)
|
|
212
226
|
if (a==0) and (b==0) and (c==0):
|
|
213
227
|
return main
|
|
228
|
+
|
|
214
229
|
mirror_obj = main
|
|
215
230
|
if make_copy:
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
else:
|
|
220
|
-
gmsh.model.occ.mirror(main.dimtags, a,b,c,d)
|
|
221
|
-
|
|
231
|
+
mirror_obj = main.make_copy()
|
|
232
|
+
gmsh.model.occ.mirror(mirror_obj.dimtags, a,b,c,d)
|
|
233
|
+
|
|
222
234
|
for fp in mirror_obj._all_pointers:
|
|
223
235
|
fp.mirror(origin, direction)
|
|
224
236
|
return mirror_obj
|
|
@@ -237,7 +249,7 @@ def change_coordinate_system(main: GeoObject,
|
|
|
237
249
|
old_cs (CoordinateSystem, optional): The old coordinate system. Defaults to GCS.
|
|
238
250
|
|
|
239
251
|
Returns:
|
|
240
|
-
|
|
252
|
+
GeoObject: The output object
|
|
241
253
|
"""
|
|
242
254
|
if new_cs._is_global and old_cs._is_global:
|
|
243
255
|
return main
|
|
@@ -254,4 +266,66 @@ def change_coordinate_system(main: GeoObject,
|
|
|
254
266
|
for fp in main._all_pointers:
|
|
255
267
|
fp.affine_transform(M1)
|
|
256
268
|
fp.affine_transform(M2)
|
|
257
|
-
return main
|
|
269
|
+
return main
|
|
270
|
+
|
|
271
|
+
@overload
|
|
272
|
+
def unite(*objects: GeoVolume) -> GeoVolume: ...
|
|
273
|
+
|
|
274
|
+
@overload
|
|
275
|
+
def unite(*objects: GeoSurface) -> GeoSurface: ...
|
|
276
|
+
|
|
277
|
+
@overload
|
|
278
|
+
def unite(*objects: GeoEdge) -> GeoEdge: ...
|
|
279
|
+
|
|
280
|
+
@overload
|
|
281
|
+
def unite(*objects: GeoPolygon) -> GeoSurface: ...
|
|
282
|
+
|
|
283
|
+
def unite(*objects: GeoObject) -> GeoObject:
|
|
284
|
+
"""Applies a fusion consisting of all geometries in the argument.
|
|
285
|
+
|
|
286
|
+
Returns:
|
|
287
|
+
GeoObject: The resultant object
|
|
288
|
+
"""
|
|
289
|
+
main, *rest = objects
|
|
290
|
+
if not rest:
|
|
291
|
+
return main
|
|
292
|
+
main._exists = False
|
|
293
|
+
dts = []
|
|
294
|
+
for other in rest:
|
|
295
|
+
dts.extend(other.dimtags)
|
|
296
|
+
other._exists = False
|
|
297
|
+
|
|
298
|
+
new_dimtags, mapping = gmsh.model.occ.fuse(main.dimtags, dts)
|
|
299
|
+
|
|
300
|
+
new_obj = GeoObject.from_dimtags(new_dimtags)._take_tools(*objects)
|
|
301
|
+
new_obj.set_material(main.material)
|
|
302
|
+
new_obj.prio_set(main._priority)
|
|
303
|
+
|
|
304
|
+
return new_obj
|
|
305
|
+
|
|
306
|
+
def expand_surface(surface: GeoSurface, distance: float) -> GeoSurface:
|
|
307
|
+
"""EXPERIMENTAL: Expands an input surface. The surface must exist on a 2D plane.
|
|
308
|
+
|
|
309
|
+
The output surface does not inherit material properties.
|
|
310
|
+
|
|
311
|
+
If any problems occur, reach out through email.
|
|
312
|
+
|
|
313
|
+
Args:
|
|
314
|
+
surface (GeoSurface): The input surface to expand
|
|
315
|
+
distance (float): The exapansion distance
|
|
316
|
+
|
|
317
|
+
Returns:
|
|
318
|
+
GeoSurface: The output surface
|
|
319
|
+
"""
|
|
320
|
+
surfs = []
|
|
321
|
+
for tag in surface.tags:
|
|
322
|
+
looptags, _ = gmsh.model.occ.get_curve_loops(tag)
|
|
323
|
+
new_curves = []
|
|
324
|
+
for looptag in looptags:
|
|
325
|
+
curve_tags = gmsh.model.occ.offset_curve(looptag, distance)
|
|
326
|
+
loop_tag = gmsh.model.occ.addCurveLoop([t for d,t in curve_tags])
|
|
327
|
+
new_curves.append(loop_tag)
|
|
328
|
+
surftag = gmsh.model.occ.addPlaneSurface(new_curves)
|
|
329
|
+
surfs.append(surftag)
|
|
330
|
+
surf = GeoSurface(surfs)
|
|
331
|
+
return surf
|
|
@@ -22,7 +22,7 @@ from ..geometry import GeoPolygon, GeoVolume, GeoSurface
|
|
|
22
22
|
from ..material import Material, AIR, COPPER
|
|
23
23
|
from .shapes import Box, Plate, Cylinder
|
|
24
24
|
from .polybased import XYPolygon
|
|
25
|
-
from .operations import change_coordinate_system
|
|
25
|
+
from .operations import change_coordinate_system, unite
|
|
26
26
|
from .pcb_tools.macro import parse_macro
|
|
27
27
|
from .pcb_tools.calculator import PCBCalculator
|
|
28
28
|
|
|
@@ -310,7 +310,6 @@ class StripCurve(StripTurn):
|
|
|
310
310
|
points: list[tuple[float, float]] = []
|
|
311
311
|
Npts = int(np.ceil(abs(self.angle/self.dang)))
|
|
312
312
|
R = self.radius-np.sign(self.angle)*self.width/2
|
|
313
|
-
print(R, self.circ_origin, self._xhat, self._yhat)
|
|
314
313
|
for i in range(Npts):
|
|
315
314
|
ang = abs((i+1)/Npts * self.angle * np.pi/180)
|
|
316
315
|
pnew = self.circ_origin + R*(self._xhat*np.cos(ang)+self._yhat*np.sin(ang))
|
|
@@ -324,7 +323,6 @@ class StripCurve(StripTurn):
|
|
|
324
323
|
|
|
325
324
|
Npts = int(np.ceil(abs(self.angle/self.dang)))
|
|
326
325
|
R = self.radius+np.sign(self.angle)*self.width/2
|
|
327
|
-
print(R, self.circ_origin, self._xhat, self._yhat)
|
|
328
326
|
for i in range(Npts):
|
|
329
327
|
ang = abs((i+1)/Npts * self.angle * np.pi/180)
|
|
330
328
|
pnew = self.circ_origin + R*(self._xhat*np.cos(ang)+self._yhat*np.sin(ang))
|
|
@@ -965,8 +963,18 @@ class PCB:
|
|
|
965
963
|
Returns:
|
|
966
964
|
float: the z-height
|
|
967
965
|
"""
|
|
966
|
+
if layer <= 0:
|
|
967
|
+
return self._zs[layer]
|
|
968
968
|
return self._zs[layer-1]
|
|
969
969
|
|
|
970
|
+
@property
|
|
971
|
+
def top(self) -> float:
|
|
972
|
+
return self._zs[-1]
|
|
973
|
+
|
|
974
|
+
@property
|
|
975
|
+
def bottom(self) -> float:
|
|
976
|
+
return self._zs[0]
|
|
977
|
+
|
|
970
978
|
def _get_z(self, element: RouteElement) -> float :
|
|
971
979
|
"""Return the z-height of a given Route Element
|
|
972
980
|
|
|
@@ -981,6 +989,31 @@ class PCB:
|
|
|
981
989
|
return path.z
|
|
982
990
|
raise RouteException('Requesting z-height of route element that is not contained in a path.')
|
|
983
991
|
|
|
992
|
+
def add_vias(self, *coordinates: tuple[float, float], radius: float,
|
|
993
|
+
z1: float | None = None,
|
|
994
|
+
z2: float | None = None,
|
|
995
|
+
segments: int = 6) -> None:
|
|
996
|
+
"""Add a series of vias provided by a list of coordinates.
|
|
997
|
+
|
|
998
|
+
Make sure to define the radius explicitly, otherwise the radius gets interpreted as a coordinate:
|
|
999
|
+
|
|
1000
|
+
>>> pcb.add_vias((x1,y1), (x1,y2), radius=1)
|
|
1001
|
+
|
|
1002
|
+
Args:
|
|
1003
|
+
*coordinates (tuple(float, float)): A series of coordinates
|
|
1004
|
+
radius (float): The radius
|
|
1005
|
+
z1 (float | None, optional): The bottom z-coordinate. Defaults to None.
|
|
1006
|
+
z2 (float | None, optional): The top z-coordinate. Defaults to None.
|
|
1007
|
+
segments (int, optional): The number of segmets for the via. Defaults to 6.
|
|
1008
|
+
"""
|
|
1009
|
+
if z1 is None:
|
|
1010
|
+
z1 = self.z(0)
|
|
1011
|
+
if z2 is None:
|
|
1012
|
+
z2 = self.z(-1)
|
|
1013
|
+
|
|
1014
|
+
for x,y in coordinates:
|
|
1015
|
+
self.vias.append(Via(x,y,z1,z2,radius,segments))
|
|
1016
|
+
|
|
984
1017
|
def load(self, name: str) -> StripLine:
|
|
985
1018
|
"""Acquire the x,y, coordinate associated with the label name.
|
|
986
1019
|
|
|
@@ -1062,7 +1095,7 @@ class PCB:
|
|
|
1062
1095
|
GeoSurface: _description_
|
|
1063
1096
|
"""
|
|
1064
1097
|
if width is None or height is None or origin is None:
|
|
1065
|
-
if self.width is None or self.length is None or self.origin:
|
|
1098
|
+
if self.width is None or self.length is None or self.origin is None:
|
|
1066
1099
|
raise RouteException('Cannot define a plane with no possible definition of its size.')
|
|
1067
1100
|
width = self.width
|
|
1068
1101
|
height = self.length
|
|
@@ -1077,6 +1110,7 @@ class PCB:
|
|
|
1077
1110
|
|
|
1078
1111
|
plane = Plate(origin, (width*self.unit, 0, 0), (0, height*self.unit, 0)) # type: ignore
|
|
1079
1112
|
plane = change_coordinate_system(plane, self.cs) # type: ignore
|
|
1113
|
+
plane.set_material(COPPER)
|
|
1080
1114
|
return plane # type: ignore
|
|
1081
1115
|
|
|
1082
1116
|
def generate_pcb(self,
|
|
@@ -1123,7 +1157,7 @@ class PCB:
|
|
|
1123
1157
|
"""Generate the Air Block object
|
|
1124
1158
|
|
|
1125
1159
|
This requires that the width, depth and origin are deterimed. This
|
|
1126
|
-
can either be done manually or via the .
|
|
1160
|
+
can either be done manually or via the .determine_bounds() method.
|
|
1127
1161
|
|
|
1128
1162
|
Returns:
|
|
1129
1163
|
GeoVolume: The PCB Block
|
|
@@ -1247,7 +1281,13 @@ class PCB:
|
|
|
1247
1281
|
plate = change_coordinate_system(plate, self.cs)
|
|
1248
1282
|
return plate # type: ignore
|
|
1249
1283
|
|
|
1250
|
-
|
|
1284
|
+
@overload
|
|
1285
|
+
def generate_vias(self, merge=Literal[True]) -> GeoVolume: ...
|
|
1286
|
+
|
|
1287
|
+
@overload
|
|
1288
|
+
def generate_vias(self, merge=Literal[False]) -> list[Cylinder]: ...
|
|
1289
|
+
|
|
1290
|
+
def generate_vias(self, merge=False) -> list[Cylinder] | GeoVolume:
|
|
1251
1291
|
"""Generates the via objects.
|
|
1252
1292
|
|
|
1253
1293
|
Args:
|
|
@@ -1321,7 +1361,7 @@ class PCB:
|
|
|
1321
1361
|
Returns:
|
|
1322
1362
|
list[Polygon] | GeoSurface: The output stripline polygons possibly merged if merge = True.
|
|
1323
1363
|
"""
|
|
1324
|
-
polys = []
|
|
1364
|
+
polys: list[GeoSurface] = []
|
|
1325
1365
|
allx = []
|
|
1326
1366
|
ally = []
|
|
1327
1367
|
|
|
@@ -1353,19 +1393,19 @@ class PCB:
|
|
|
1353
1393
|
poly = self._gen_poly(pcbpoly.xys, pcbpoly.z)
|
|
1354
1394
|
poly.material = pcbpoly.material
|
|
1355
1395
|
polys.append(poly)
|
|
1396
|
+
xs, ys = zip(*pcbpoly.xys)
|
|
1397
|
+
allx.extend(xs)
|
|
1398
|
+
ally.extend(ys)
|
|
1399
|
+
|
|
1356
1400
|
|
|
1357
1401
|
self.xs = allx
|
|
1358
1402
|
self.ys = ally
|
|
1359
1403
|
|
|
1360
1404
|
self.traces = polys
|
|
1405
|
+
|
|
1361
1406
|
if merge:
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
tags.extend(p.tags)
|
|
1365
|
-
if p.material != COPPER:
|
|
1366
|
-
logger.warning(f'Merging a polygon with material {p.material} into a single polygon that will be COPPER.')
|
|
1367
|
-
polys = GeoSurface(tags)
|
|
1368
|
-
polys.material = COPPER
|
|
1407
|
+
polys = unite(*polys)
|
|
1408
|
+
|
|
1369
1409
|
return polys
|
|
1370
1410
|
|
|
1371
1411
|
############################################################
|
|
@@ -30,10 +30,20 @@ class Alignment(Enum):
|
|
|
30
30
|
CENTER = 1
|
|
31
31
|
CORNER = 2
|
|
32
32
|
|
|
33
|
+
|
|
33
34
|
class Box(GeoVolume):
|
|
34
|
-
"""
|
|
35
|
+
"""Creates a box volume object.
|
|
36
|
+
Specify the alignment of the box with the provided position. The options are CORNER (default)
|
|
37
|
+
for the front-left-bottom node of the box or CENTER for the center of the box.
|
|
35
38
|
|
|
36
|
-
|
|
39
|
+
Args:
|
|
40
|
+
width (float): The x-size
|
|
41
|
+
depth (float): The y-size
|
|
42
|
+
height (float): The z-size
|
|
43
|
+
position (tuple, optional): The position of the box. Defaults to (0,0,0).
|
|
44
|
+
alignment (Alignment, optional): Which point of the box is placed at the position.
|
|
45
|
+
Defaults to Alignment.CORNER.
|
|
46
|
+
"""
|
|
37
47
|
|
|
38
48
|
def __init__(self,
|
|
39
49
|
width: float,
|
|
@@ -91,10 +101,15 @@ class Box(GeoVolume):
|
|
|
91
101
|
|
|
92
102
|
tags = list(reduce(lambda a,b: a+b, tagslist))
|
|
93
103
|
return FaceSelection(tags)
|
|
94
|
-
|
|
104
|
+
|
|
95
105
|
|
|
96
106
|
class Sphere(GeoVolume):
|
|
107
|
+
"""Generates a sphere objected centered ont he position with the given radius
|
|
97
108
|
|
|
109
|
+
Args:
|
|
110
|
+
radius (float): The sphere radius
|
|
111
|
+
position (tuple, optional): The center position. Defaults to (0,0,0).
|
|
112
|
+
"""
|
|
98
113
|
def __init__(self,
|
|
99
114
|
radius: float,
|
|
100
115
|
position: tuple = (0,0,0)):
|
|
@@ -108,7 +123,19 @@ class Sphere(GeoVolume):
|
|
|
108
123
|
x,y,z = position
|
|
109
124
|
self.tags: list[int] = [gmsh.model.occ.addSphere(x,y,z,radius),]
|
|
110
125
|
|
|
126
|
+
|
|
111
127
|
class XYPlate(GeoSurface):
|
|
128
|
+
"""Generates and XY-plane oriented plate
|
|
129
|
+
|
|
130
|
+
Specify the alignment of the plate with the provided position. The options are CORNER (default)
|
|
131
|
+
for the front-left node of the plate or CENTER for the center of the plate.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
width (float): The x-size of the plate
|
|
135
|
+
depth (float): The y-size of the plate
|
|
136
|
+
position (tuple, optional): The position of the alignment node. Defaults to (0,0,0).
|
|
137
|
+
alignment (Alignment, optional): Which node to align to. Defaults to Alignment.CORNER.
|
|
138
|
+
"""
|
|
112
139
|
def __init__(self,
|
|
113
140
|
width: float,
|
|
114
141
|
depth: float,
|
|
@@ -134,7 +161,19 @@ class XYPlate(GeoSurface):
|
|
|
134
161
|
|
|
135
162
|
|
|
136
163
|
class Plate(GeoSurface):
|
|
137
|
-
|
|
164
|
+
"""A generalized 2D rectangular plate in XYZ-space.
|
|
165
|
+
|
|
166
|
+
The plate is specified by an origin (o) in meters coordinate plus two vectors (u,v) in meters
|
|
167
|
+
that span two of the sides such that all points of the plate are defined by:
|
|
168
|
+
p1 = o
|
|
169
|
+
p2 = o+u
|
|
170
|
+
p3 = o+v
|
|
171
|
+
p4 = o+u+v
|
|
172
|
+
Args:
|
|
173
|
+
origin (tuple[float, float, float]): The origin of the plate in meters
|
|
174
|
+
u (tuple[float, float, float]): The u-axis of the plate
|
|
175
|
+
v (tuple[float, float, float]): The v-axis of the plate
|
|
176
|
+
"""
|
|
138
177
|
def __init__(self,
|
|
139
178
|
origin: tuple[float, float, float],
|
|
140
179
|
u: tuple[float, float, float],
|
|
@@ -172,27 +211,43 @@ class Plate(GeoSurface):
|
|
|
172
211
|
tags: list[int] = [gmsh.model.occ.addPlaneSurface([tag_wire,]),]
|
|
173
212
|
super().__init__(tags)
|
|
174
213
|
|
|
214
|
+
|
|
175
215
|
class Cylinder(GeoVolume):
|
|
216
|
+
"""Generates a Cylinder object in 3D space.
|
|
217
|
+
The cylinder will always be placed in the origin of the provided CoordinateSystem.
|
|
218
|
+
The bottom cylinder plane is always placed in the XY-plane. The length of the cylinder is
|
|
219
|
+
oriented along the Z-axis.
|
|
176
220
|
|
|
221
|
+
By default the cylinder uses the Open Cascade modeling for a cylinder. In this representation
|
|
222
|
+
the surface of the cylinder is approximated with a tolerance thay may be irregular.
|
|
223
|
+
As an alternative, the argument Nsections may be provided in which case the Cylinder is replaced
|
|
224
|
+
by an extrusion of a regular N-sided polygon.
|
|
225
|
+
|
|
226
|
+
Args:
|
|
227
|
+
radius (float): The radius of the Cylinder
|
|
228
|
+
height (float): The height of the Cylinder
|
|
229
|
+
cs (CoordinateSystem, optional): The coordinate system. Defaults to GCS.
|
|
230
|
+
Nsections (int, optional): The number of sections. Defaults to None.
|
|
231
|
+
"""
|
|
177
232
|
def __init__(self,
|
|
178
233
|
radius: float,
|
|
179
234
|
height: float,
|
|
180
|
-
cs: CoordinateSystem =
|
|
181
|
-
Nsections: int = None):
|
|
235
|
+
cs: CoordinateSystem = GCS,
|
|
236
|
+
Nsections: int | None = None):
|
|
182
237
|
"""Generates a Cylinder object in 3D space.
|
|
183
|
-
The
|
|
184
|
-
The bottom
|
|
238
|
+
The cylinder will always be placed in the origin of the provided CoordinateSystem.
|
|
239
|
+
The bottom cylinder plane is always placed in the XY-plane. The length of the cylinder is
|
|
185
240
|
oriented along the Z-axis.
|
|
186
241
|
|
|
187
|
-
By default the
|
|
188
|
-
the surface of the
|
|
242
|
+
By default the cylinder uses the Open Cascade modeling for a cylinder. In this representation
|
|
243
|
+
the surface of the cylinder is approximated with a tolerance thay may be irregular.
|
|
189
244
|
As an alternative, the argument Nsections may be provided in which case the Cylinder is replaced
|
|
190
245
|
by an extrusion of a regular N-sided polygon.
|
|
191
246
|
|
|
192
247
|
Args:
|
|
193
248
|
radius (float): The radius of the Cylinder
|
|
194
249
|
height (float): The height of the Cylinder
|
|
195
|
-
cs (CoordinateSystem, optional): The coordinate system. Defaults to
|
|
250
|
+
cs (CoordinateSystem, optional): The coordinate system. Defaults to GCS.
|
|
196
251
|
Nsections (int, optional): The number of sections. Defaults to None.
|
|
197
252
|
"""
|
|
198
253
|
ax = cs.zax.np
|
|
@@ -233,33 +288,46 @@ class Cylinder(GeoVolume):
|
|
|
233
288
|
xo, yo, zo = self.cs.in_global_cs(x.flatten(), y.flatten(), z.flatten())
|
|
234
289
|
return xo, yo, zo
|
|
235
290
|
|
|
291
|
+
|
|
236
292
|
class CoaxCylinder(GeoVolume):
|
|
237
|
-
"""
|
|
238
|
-
|
|
293
|
+
"""Generates a Coaxial cylinder object in 3D space.
|
|
294
|
+
The coaxial cylinder will always be placed in the origin of the provided CoordinateSystem.
|
|
295
|
+
The bottom coax plane is always placed in the XY-plane. The lenth of the coax is
|
|
296
|
+
oriented along the Z-axis.
|
|
297
|
+
|
|
298
|
+
By default the coax uses the Open Cascade modeling for a cylinder. In this representation
|
|
299
|
+
the surface of the cylinder is approximated with a tolerance thay may be irregular.
|
|
300
|
+
As an alternative, the argument Nsections may be provided in which case the Cylinder is replaced
|
|
301
|
+
by an extrusion of a regular N-sided polygon.
|
|
302
|
+
|
|
303
|
+
Args:
|
|
304
|
+
radius (float): The radius of the Cylinder
|
|
305
|
+
height (float): The height of the Cylinder
|
|
306
|
+
cs (CoordinateSystem, optional): The coordinate system. Defaults to GCS.
|
|
307
|
+
Nsections (int, optional): The number of sections. Defaults to None.
|
|
308
|
+
"""
|
|
239
309
|
def __init__(self,
|
|
240
310
|
rout: float,
|
|
241
311
|
rin: float,
|
|
242
312
|
height: float,
|
|
243
|
-
cs: CoordinateSystem =
|
|
244
|
-
Nsections: int = None):
|
|
245
|
-
"""Generates a Coaxial
|
|
246
|
-
The coaxial
|
|
313
|
+
cs: CoordinateSystem = GCS,
|
|
314
|
+
Nsections: int | None = None):
|
|
315
|
+
"""Generates a Coaxial cylinder object in 3D space.
|
|
316
|
+
The coaxial cylinder will always be placed in the origin of the provided CoordinateSystem.
|
|
247
317
|
The bottom coax plane is always placed in the XY-plane. The lenth of the coax is
|
|
248
318
|
oriented along the Z-axis.
|
|
249
319
|
|
|
250
|
-
By default the coax uses the Open Cascade modeling for a
|
|
251
|
-
the surface of the
|
|
320
|
+
By default the coax uses the Open Cascade modeling for a cylinder. In this representation
|
|
321
|
+
the surface of the cylinder is approximated with a tolerance thay may be irregular.
|
|
252
322
|
As an alternative, the argument Nsections may be provided in which case the Cylinder is replaced
|
|
253
323
|
by an extrusion of a regular N-sided polygon.
|
|
254
324
|
|
|
255
325
|
Args:
|
|
256
326
|
radius (float): The radius of the Cylinder
|
|
257
327
|
height (float): The height of the Cylinder
|
|
258
|
-
cs (CoordinateSystem, optional): The coordinate system. Defaults to
|
|
328
|
+
cs (CoordinateSystem, optional): The coordinate system. Defaults to GCS.
|
|
259
329
|
Nsections (int, optional): The number of sections. Defaults to None.
|
|
260
330
|
"""
|
|
261
|
-
if cs is None:
|
|
262
|
-
cs = GCS
|
|
263
331
|
if rout <= rin:
|
|
264
332
|
raise ValueError("Outer radius must be greater than inner radius.")
|
|
265
333
|
|
|
@@ -297,10 +365,9 @@ class CoaxCylinder(GeoVolume):
|
|
|
297
365
|
|
|
298
366
|
xo, yo, zo = self.cs.in_global_cs(x.flatten(), y.flatten(), z.flatten())
|
|
299
367
|
return xo, yo, zo
|
|
300
|
-
return super().boundary()
|
|
301
368
|
|
|
302
369
|
class HalfSphere(GeoVolume):
|
|
303
|
-
|
|
370
|
+
"""A half sphere volume."""
|
|
304
371
|
def __init__(self,
|
|
305
372
|
radius: float,
|
|
306
373
|
position: tuple = (0,0,0),
|
|
@@ -326,8 +393,6 @@ class HalfSphere(GeoVolume):
|
|
|
326
393
|
self._add_face_pointer('back',np.array(position), np.array(direction))
|
|
327
394
|
self._add_face_pointer('bottom',np.array(position), np.array(direction))
|
|
328
395
|
self._add_face_pointer('face',np.array(position), np.array(direction))
|
|
329
|
-
|
|
330
|
-
|
|
331
396
|
|
|
332
397
|
|
|
333
398
|
class OldBox(GeoVolume):
|
|
@@ -353,8 +418,6 @@ class OldBox(GeoVolume):
|
|
|
353
418
|
alignment (Alignment, optional): Which point of the box is placed at the position.
|
|
354
419
|
Defaults to Alignment.CORNER.
|
|
355
420
|
"""
|
|
356
|
-
|
|
357
|
-
|
|
358
421
|
if alignment is Alignment.CORNER:
|
|
359
422
|
position = (position[0]+width/2, position[1]+depth/2, position[2])
|
|
360
423
|
elif alignment is Alignment.CENTER:
|
|
@@ -436,7 +499,6 @@ class OldBox(GeoVolume):
|
|
|
436
499
|
self._add_face_pointer('right', pc + width/2*wax, wax)
|
|
437
500
|
self._add_face_pointer('top', pc + height/2*hax, hax)
|
|
438
501
|
self._add_face_pointer('bottom', pc - height/2*hax, -hax)
|
|
439
|
-
|
|
440
502
|
|
|
441
503
|
def outside(self, *exclude: Literal['bottom','top','right','left','front','back']) -> FaceSelection:
|
|
442
504
|
"""Select all outside faces except for the once specified by outside
|
|
@@ -449,8 +511,17 @@ class OldBox(GeoVolume):
|
|
|
449
511
|
tags = list(reduce(lambda a,b: a+b, tagslist))
|
|
450
512
|
return FaceSelection(tags)
|
|
451
513
|
|
|
514
|
+
|
|
452
515
|
class Cone(GeoVolume):
|
|
453
|
-
|
|
516
|
+
"""Constructis a cone that starts at position p0 and is aimed in the given direction.
|
|
517
|
+
r1 is the start radius and r2 the end radius. The magnitude of direction determines its length.
|
|
518
|
+
|
|
519
|
+
Args:
|
|
520
|
+
p0 (tuple[float, float, float]): _description_
|
|
521
|
+
direction (tuple[float, float, float]): _description_
|
|
522
|
+
r1 (float): _description_
|
|
523
|
+
r2 (float): _description_
|
|
524
|
+
"""
|
|
454
525
|
def __init__(self, p0: tuple[float, float, float],
|
|
455
526
|
direction: tuple[float, float, float],
|
|
456
527
|
r1: float,
|