Skip to content

Commit 943b0ba

Browse files
Reduce the number of vertices for smoothly curved cross section
1 parent bc43042 commit 943b0ba

File tree

6 files changed

+188
-32
lines changed

6 files changed

+188
-32
lines changed

tidy3d/components/geometry/base.py

Lines changed: 114 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,12 @@ def inside_meshgrid(
228228

229229
@abstractmethod
230230
def intersections_tilted_plane(
231-
self, normal: Coordinate, origin: Coordinate, to_2D: MatrixReal4x4, cleanup: bool = True
231+
self,
232+
normal: Coordinate,
233+
origin: Coordinate,
234+
to_2D: MatrixReal4x4,
235+
cleanup: bool = True,
236+
quad_segs: Optional[int] = None,
232237
) -> list[Shapely]:
233238
"""Return a list of shapely geometries at the plane specified by normal and origin.
234239
@@ -242,6 +247,9 @@ def intersections_tilted_plane(
242247
Transformation matrix to apply to resulting shapes.
243248
cleanup : bool = True
244249
If True, removes extremely small features from each polygon's boundary.
250+
quad_segs : Optional[int] = None
251+
Number of segments used to discretize circular shapes. If ``None``, uses
252+
high-quality visualization settings.
245253
246254
Returns
247255
-------
@@ -257,6 +265,7 @@ def intersections_plane(
257265
y: Optional[float] = None,
258266
z: Optional[float] = None,
259267
cleanup: bool = True,
268+
quad_segs: Optional[int] = None,
260269
) -> list[Shapely]:
261270
"""Returns list of shapely geometries at plane specified by one non-None value of x,y,z.
262271
@@ -270,6 +279,9 @@ def intersections_plane(
270279
Position of plane in z direction, only one of x,y,z can be specified to define plane.
271280
cleanup : bool = True
272281
If True, removes extremely small features from each polygon's boundary.
282+
quad_segs : Optional[int] = None
283+
Number of segments used to discretize circular shapes. If ``None``, uses
284+
high-quality visualization settings.
273285
274286
Returns
275287
-------
@@ -285,7 +297,9 @@ def intersections_plane(
285297
if axis != 2:
286298
last, indices = self.pop_axis((0, 1, 2), axis)
287299
to_2D = to_2D[[*list(indices), last, 3]]
288-
return self.intersections_tilted_plane(normal, origin, to_2D, cleanup=cleanup)
300+
return self.intersections_tilted_plane(
301+
normal, origin, to_2D, cleanup=cleanup, quad_segs=quad_segs
302+
)
289303

290304
def intersections_2dbox(self, plane: Box) -> list[Shapely]:
291305
"""Returns list of shapely geometries representing the intersections of the geometry with
@@ -1571,7 +1585,12 @@ class SimplePlaneIntersection(Geometry, ABC):
15711585
"""A geometry where intersections with an axis aligned plane may be computed efficiently."""
15721586

15731587
def intersections_tilted_plane(
1574-
self, normal: Coordinate, origin: Coordinate, to_2D: MatrixReal4x4, cleanup: bool = True
1588+
self,
1589+
normal: Coordinate,
1590+
origin: Coordinate,
1591+
to_2D: MatrixReal4x4,
1592+
cleanup: bool = True,
1593+
quad_segs: Optional[int] = None,
15751594
) -> list[Shapely]:
15761595
"""Return a list of shapely geometries at the plane specified by normal and origin.
15771596
Checks special cases before relying on the complete computation.
@@ -1586,6 +1605,9 @@ def intersections_tilted_plane(
15861605
Transformation matrix to apply to resulting shapes.
15871606
cleanup : bool = True
15881607
If True, removes extremely small features from each polygon's boundary.
1608+
quad_segs : Optional[int] = None
1609+
Number of segments used to discretize circular shapes. If ``None``, uses
1610+
high-quality visualization settings.
15891611
15901612
Returns
15911613
-------
@@ -1600,7 +1622,7 @@ def intersections_tilted_plane(
16001622
axis = np.argmax(np.abs(normal)).item()
16011623
coord = "xyz"[axis]
16021624
kwargs = {coord: origin[axis]}
1603-
section = self.intersections_plane(cleanup=cleanup, **kwargs)
1625+
section = self.intersections_plane(cleanup=cleanup, quad_segs=quad_segs, **kwargs)
16041626
# Apply transformation in the plane by removing row and column
16051627
to_2D_in_plane = np.delete(np.delete(to_2D, 2, 0), axis, 1)
16061628

@@ -1612,11 +1634,17 @@ def transform(p_array: NDArray) -> NDArray:
16121634
transformed_section = shapely.transform(section, transformation=transform)
16131635
return transformed_section
16141636
# Otherwise compute the arbitrary intersection
1615-
return self._do_intersections_tilted_plane(normal=normal, origin=origin, to_2D=to_2D)
1637+
return self._do_intersections_tilted_plane(
1638+
normal=normal, origin=origin, to_2D=to_2D, quad_segs=quad_segs
1639+
)
16161640

16171641
@abstractmethod
16181642
def _do_intersections_tilted_plane(
1619-
self, normal: Coordinate, origin: Coordinate, to_2D: MatrixReal4x4
1643+
self,
1644+
normal: Coordinate,
1645+
origin: Coordinate,
1646+
to_2D: MatrixReal4x4,
1647+
quad_segs: Optional[int] = None,
16201648
) -> list[Shapely]:
16211649
"""Return a list of shapely geometries at the plane specified by normal and origin.
16221650
@@ -1628,6 +1656,8 @@ def _do_intersections_tilted_plane(
16281656
Vector defining the plane origin.
16291657
to_2D : MatrixReal4x4
16301658
Transformation matrix to apply to resulting shapes.
1659+
quad_segs : Optional[int] = None
1660+
Number of segments used to discretize circular shapes.
16311661
16321662
Returns
16331663
-------
@@ -1718,6 +1748,7 @@ def intersections_plane(
17181748
y: Optional[float] = None,
17191749
z: Optional[float] = None,
17201750
cleanup: bool = True,
1751+
quad_segs: Optional[int] = None,
17211752
) -> list[Shapely]:
17221753
"""Returns shapely geometry at plane specified by one non None value of x,y,z.
17231754
@@ -1731,6 +1762,9 @@ def intersections_plane(
17311762
Position of plane in z direction, only one of x,y,z can be specified to define plane.
17321763
cleanup : bool = True
17331764
If True, removes extremely small features from each polygon's boundary.
1765+
quad_segs : Optional[int] = None
1766+
Number of segments used to discretize circular shapes. If ``None``, uses
1767+
high-quality visualization settings.
17341768
17351769
Returns
17361770
-------
@@ -1743,17 +1777,20 @@ def intersections_plane(
17431777
if not self.intersects_axis_position(axis, position):
17441778
return []
17451779
if axis == self.axis:
1746-
return self._intersections_normal(position)
1780+
return self._intersections_normal(position, quad_segs=quad_segs)
17471781
return self._intersections_side(position, axis)
17481782

17491783
@abstractmethod
1750-
def _intersections_normal(self, z: float) -> list:
1784+
def _intersections_normal(self, z: float, quad_segs: Optional[int] = None) -> list:
17511785
"""Find shapely geometries intersecting planar geometry with axis normal to slab.
17521786
17531787
Parameters
17541788
----------
17551789
z : float
17561790
Position along the axis normal to slab
1791+
quad_segs : Optional[int] = None
1792+
Number of segments used to discretize circular shapes. If ``None``, uses
1793+
high-quality visualization settings.
17571794
17581795
Returns
17591796
-------
@@ -2091,6 +2128,7 @@ def intersections_plane(
20912128
y: Optional[float] = None,
20922129
z: Optional[float] = None,
20932130
cleanup: bool = True,
2131+
quad_segs: Optional[int] = None,
20942132
) -> list[Shapely]:
20952133
"""Returns shapely geometry at plane specified by one non None value of x,y,z.
20962134
@@ -2104,6 +2142,8 @@ def intersections_plane(
21042142
Position of plane in z direction, only one of x,y,z can be specified to define plane.
21052143
cleanup : bool = True
21062144
If True, removes extremely small features from each polygon's boundary.
2145+
quad_segs : Optional[int] = None
2146+
Number of segments used to discretize circular shapes. Not used for Box geometry.
21072147
21082148
Returns
21092149
-------
@@ -2159,10 +2199,22 @@ def inside(self, x: NDArray[float], y: NDArray[float], z: NDArray[float]) -> NDA
21592199
dist_z = np.abs(z - z0)
21602200
return (dist_x <= Lx / 2) * (dist_y <= Ly / 2) * (dist_z <= Lz / 2)
21612201

2162-
def intersections_with(self, other: Shapely, cleanup: bool = True) -> list[Shapely]:
2202+
def intersections_with(
2203+
self, other: Shapely, cleanup: bool = True, quad_segs: Optional[int] = None
2204+
) -> list[Shapely]:
21632205
"""Returns list of shapely geometries representing the intersections of the geometry with
21642206
this 2D box.
21652207
2208+
Parameters
2209+
----------
2210+
other : Shapely
2211+
Geometry to intersect with.
2212+
cleanup : bool = True
2213+
If True, removes extremely small features from each polygon's boundary.
2214+
quad_segs : Optional[int] = None
2215+
Number of segments used to discretize circular shapes. If ``None``, uses
2216+
high-quality visualization settings.
2217+
21662218
Returns
21672219
-------
21682220
List[shapely.geometry.base.BaseGeometry]
@@ -2186,7 +2238,7 @@ def intersections_with(self, other: Shapely, cleanup: bool = True) -> list[Shape
21862238
dim = "xyz"[normal_ind]
21872239
pos = self.center[normal_ind]
21882240
xyz_kwargs = {dim: pos}
2189-
shapes_plane = other.intersections_plane(cleanup=cleanup, **xyz_kwargs)
2241+
shapes_plane = other.intersections_plane(cleanup=cleanup, quad_segs=quad_segs, **xyz_kwargs)
21902242

21912243
# intersect all shapes with the input self
21922244
bs_min, bs_max = (self.pop_axis(bounds, axis=normal_ind)[1] for bounds in self.bounds)
@@ -2778,7 +2830,12 @@ def bounds(self) -> Bound:
27782830
return (tuple(vertices.min(axis=1)), tuple(vertices.max(axis=1)))
27792831

27802832
def intersections_tilted_plane(
2781-
self, normal: Coordinate, origin: Coordinate, to_2D: MatrixReal4x4, cleanup: bool = True
2833+
self,
2834+
normal: Coordinate,
2835+
origin: Coordinate,
2836+
to_2D: MatrixReal4x4,
2837+
cleanup: bool = True,
2838+
quad_segs: Optional[int] = None,
27822839
) -> list[Shapely]:
27832840
"""Return a list of shapely geometries at the plane specified by normal and origin.
27842841
@@ -2792,6 +2849,9 @@ def intersections_tilted_plane(
27922849
Transformation matrix to apply to resulting shapes.
27932850
cleanup : bool = True
27942851
If True, removes extremely small features from each polygon's boundary.
2852+
quad_segs : Optional[int] = None
2853+
Number of segments used to discretize circular shapes. If ``None``, uses
2854+
high-quality visualization settings.
27952855
27962856
Returns
27972857
-------
@@ -2805,6 +2865,7 @@ def intersections_tilted_plane(
28052865
tuple(np.dot(self.inverse, (origin[0], origin[1], origin[2], 1.0))[:3]),
28062866
np.dot(to_2D, self.transform),
28072867
cleanup=cleanup,
2868+
quad_segs=quad_segs,
28082869
)
28092870

28102871
def inside(self, x: NDArray[float], y: NDArray[float], z: NDArray[float]) -> NDArray[bool]:
@@ -3090,7 +3151,12 @@ def _bit_operation(self) -> Callable[[Any, Any], Any]:
30903151
return result
30913152

30923153
def intersections_tilted_plane(
3093-
self, normal: Coordinate, origin: Coordinate, to_2D: MatrixReal4x4, cleanup: bool = True
3154+
self,
3155+
normal: Coordinate,
3156+
origin: Coordinate,
3157+
to_2D: MatrixReal4x4,
3158+
cleanup: bool = True,
3159+
quad_segs: Optional[int] = None,
30943160
) -> list[Shapely]:
30953161
"""Return a list of shapely geometries at the plane specified by normal and origin.
30963162
@@ -3102,6 +3168,11 @@ def intersections_tilted_plane(
31023168
Vector defining the plane origin.
31033169
to_2D : MatrixReal4x4
31043170
Transformation matrix to apply to resulting shapes.
3171+
cleanup : bool = True
3172+
If True, removes extremely small features from each polygon's boundary.
3173+
quad_segs : Optional[int] = None
3174+
Number of segments used to discretize circular shapes. If ``None``, uses
3175+
high-quality visualization settings.
31053176
31063177
Returns
31073178
-------
@@ -3110,8 +3181,12 @@ def intersections_tilted_plane(
31103181
For more details refer to
31113182
`Shapely's Documentation <https://shapely.readthedocs.io/en/stable/project.html>`_.
31123183
"""
3113-
a = self.geometry_a.intersections_tilted_plane(normal, origin, to_2D, cleanup=cleanup)
3114-
b = self.geometry_b.intersections_tilted_plane(normal, origin, to_2D, cleanup=cleanup)
3184+
a = self.geometry_a.intersections_tilted_plane(
3185+
normal, origin, to_2D, cleanup=cleanup, quad_segs=quad_segs
3186+
)
3187+
b = self.geometry_b.intersections_tilted_plane(
3188+
normal, origin, to_2D, cleanup=cleanup, quad_segs=quad_segs
3189+
)
31153190
geom_a = shapely.unary_union([Geometry.evaluate_inf_shape(g) for g in a])
31163191
geom_b = shapely.unary_union([Geometry.evaluate_inf_shape(g) for g in b])
31173192
return ClipOperation.to_polygon_list(
@@ -3125,6 +3200,7 @@ def intersections_plane(
31253200
y: Optional[float] = None,
31263201
z: Optional[float] = None,
31273202
cleanup: bool = True,
3203+
quad_segs: Optional[int] = None,
31283204
) -> list[Shapely]:
31293205
"""Returns list of shapely geometries at plane specified by one non-None value of x,y,z.
31303206
@@ -3136,6 +3212,11 @@ def intersections_plane(
31363212
Position of plane in y direction, only one of x,y,z can be specified to define plane.
31373213
z : float = None
31383214
Position of plane in z direction, only one of x,y,z can be specified to define plane.
3215+
cleanup : bool = True
3216+
If True, removes extremely small features from each polygon's boundary.
3217+
quad_segs : Optional[int] = None
3218+
Number of segments used to discretize circular shapes. If ``None``, uses
3219+
high-quality visualization settings.
31393220
31403221
Returns
31413222
-------
@@ -3144,8 +3225,8 @@ def intersections_plane(
31443225
For more details refer to
31453226
`Shapely's Documentaton <https://shapely.readthedocs.io/en/stable/project.html>`_.
31463227
"""
3147-
a = self.geometry_a.intersections_plane(x, y, z, cleanup=cleanup)
3148-
b = self.geometry_b.intersections_plane(x, y, z, cleanup=cleanup)
3228+
a = self.geometry_a.intersections_plane(x, y, z, cleanup=cleanup, quad_segs=quad_segs)
3229+
b = self.geometry_b.intersections_plane(x, y, z, cleanup=cleanup, quad_segs=quad_segs)
31493230
geom_a = shapely.unary_union([Geometry.evaluate_inf_shape(g) for g in a])
31503231
geom_b = shapely.unary_union([Geometry.evaluate_inf_shape(g) for g in b])
31513232
return ClipOperation.to_polygon_list(
@@ -3308,7 +3389,12 @@ def bounds(self) -> Bound:
33083389
)
33093390

33103391
def intersections_tilted_plane(
3311-
self, normal: Coordinate, origin: Coordinate, to_2D: MatrixReal4x4, cleanup: bool = True
3392+
self,
3393+
normal: Coordinate,
3394+
origin: Coordinate,
3395+
to_2D: MatrixReal4x4,
3396+
cleanup: bool = True,
3397+
quad_segs: Optional[int] = None,
33123398
) -> list[Shapely]:
33133399
"""Return a list of shapely geometries at the plane specified by normal and origin.
33143400
@@ -3322,6 +3408,9 @@ def intersections_tilted_plane(
33223408
Transformation matrix to apply to resulting shapes.
33233409
cleanup : bool = True
33243410
If True, removes extremely small features from each polygon's boundary.
3411+
quad_segs : Optional[int] = None
3412+
Number of segments used to discretize circular shapes. If ``None``, uses
3413+
high-quality visualization settings.
33253414
33263415
Returns
33273416
-------
@@ -3334,7 +3423,7 @@ def intersections_tilted_plane(
33343423
intersection
33353424
for geometry in self.geometries
33363425
for intersection in geometry.intersections_tilted_plane(
3337-
normal, origin, to_2D, cleanup=cleanup
3426+
normal, origin, to_2D, cleanup=cleanup, quad_segs=quad_segs
33383427
)
33393428
]
33403429

@@ -3344,6 +3433,7 @@ def intersections_plane(
33443433
y: Optional[float] = None,
33453434
z: Optional[float] = None,
33463435
cleanup: bool = True,
3436+
quad_segs: Optional[int] = None,
33473437
) -> list[Shapely]:
33483438
"""Returns list of shapely geometries at plane specified by one non-None value of x,y,z.
33493439
@@ -3357,6 +3447,9 @@ def intersections_plane(
33573447
Position of plane in z direction, only one of x,y,z can be specified to define plane.
33583448
cleanup : bool = True
33593449
If True, removes extremely small features from each polygon's boundary.
3450+
quad_segs : Optional[int] = None
3451+
Number of segments used to discretize circular shapes. If ``None``, uses
3452+
high-quality visualization settings.
33603453
33613454
Returns
33623455
-------
@@ -3370,7 +3463,9 @@ def intersections_plane(
33703463
return [
33713464
intersection
33723465
for geometry in self.geometries
3373-
for intersection in geometry.intersections_plane(x=x, y=y, z=z, cleanup=cleanup)
3466+
for intersection in geometry.intersections_plane(
3467+
x=x, y=y, z=z, cleanup=cleanup, quad_segs=quad_segs
3468+
)
33743469
]
33753470

33763471
def intersects_axis_position(self, axis: float, position: float) -> bool:

0 commit comments

Comments
 (0)