From 295f85249ba8a989dce61327a1b5f1db16d4d461 Mon Sep 17 00:00:00 2001 From: Keurfon Luu Date: Fri, 28 Feb 2025 18:23:55 +0100 Subject: [PATCH 1/2] add option constrain_edge_size --- src/skgmsh/__init__.py | 42 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/src/skgmsh/__init__.py b/src/skgmsh/__init__.py index 9ecd89e2..99638396 100644 --- a/src/skgmsh/__init__.py +++ b/src/skgmsh/__init__.py @@ -9,6 +9,8 @@ from typing import Optional import gmsh +import numpy as np +from numpy.typing import ArrayLike from pygmsh.helpers import extract_to_meshio import pyvista as pv import scooby @@ -244,14 +246,21 @@ def frontal_delaunay_2d( # noqa: C901, PLR0912 if isinstance(edge_source, shapely.geometry.Polygon): wire_tags = [] - for linearring in [edge_source.exterior, *list(edge_source.interiors)]: + + if isinstance(target_sizes, float): + target_sizes = [target_sizes] * (len(edge_source.interiors) + 1) + + for target_size, linearring in zip(target_sizes, [edge_source.exterior, *list(edge_source.interiors)]): + if isinstance(target_size, float): + target_size = [target_size] * (len(linearring.coords) - 1) + coords = linearring.coords[:-1].copy() tags = [] - for coord in coords: + for size, coord in zip(target_size, coords): x = coord[0] y = coord[1] z = coord[2] - tags.append(gmsh.model.geo.add_point(x, y, z, target_sizes)) + tags.append(gmsh.model.geo.add_point(x, y, z, size)) curve_tags = [] for i, _ in enumerate(tags): start_tag = tags[i - 1] @@ -317,11 +326,14 @@ class Delaunay2D: holes : sequence A sequence of objects which satisfy the same requirements as the - shell parameters above + shell parameters above. cell_size : float Meshing constraint at point. + constrain_edge_size : bool + If True, cell size at points are set to their maximum edge length. + Notes ----- .. versionadded:: 0.2.0 @@ -335,14 +347,36 @@ def __init__( shell: Sequence[tuple[int]] | None = None, holes: Sequence[tuple[int]] | None = None, cell_size: float | None = None, + constrain_edge_size: bool = False, ) -> None: """Initialize the Delaunay2D class.""" if edge_source is not None: self._edge_source = edge_source else: self._edge_source = shapely.Polygon(shell, holes) + + if constrain_edge_size: + if isinstance(self.edge_source, shapely.Polygon): + cell_size = [self._compute_cell_size_from_points(self.edge_source.exterior.coords)] + cell_size += [self._compute_cell_size_from_points(hole.coords) for hole in self.edge_source.interiors] + + else: + # Only the first line is processed + lines = edge_source.lines + line = lines[1 : lines[0] + 1] + edge_points = edge_source.points[line] + cell_size = self._compute_cell_size_from_points(edge_points) + self._cell_size = cell_size + @staticmethod + def _compute_cell_size_from_points(points: ArrayLike) -> ArrayLike: + """Compute cell size from points array.""" + lengths = np.linalg.norm(np.diff(points, axis=0), axis=-1) + lengths = np.insert(lengths, 0, lengths[-1]) + + return np.maximum(lengths[:-1], lengths[1:]) + @property def edge_source(self: Delaunay2D) -> pv.PolyData | shapely.geometry.Polygon: """Get the edge source.""" From 4a27b58813f8293076752680d4612d41c903318f Mon Sep 17 00:00:00 2001 From: Keurfon Luu Date: Fri, 28 Feb 2025 18:37:25 +0100 Subject: [PATCH 2/2] pre commit --- src/skgmsh/__init__.py | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/skgmsh/__init__.py b/src/skgmsh/__init__.py index 99638396..50032612 100644 --- a/src/skgmsh/__init__.py +++ b/src/skgmsh/__init__.py @@ -10,7 +10,6 @@ import gmsh import numpy as np -from numpy.typing import ArrayLike from pygmsh.helpers import extract_to_meshio import pyvista as pv import scooby @@ -19,6 +18,8 @@ if TYPE_CHECKING: from collections.abc import Sequence + from numpy.typing import ArrayLike + INITIAL_MESH_ONLY_2D = 3 FRONTAL_DELAUNAY_2D = 6 DELAUNAY_3D = 1 @@ -198,7 +199,7 @@ def delaunay_3d( def frontal_delaunay_2d( # noqa: C901, PLR0912 edge_source: pv.PolyData | shapely.geometry.Polygon, - target_sizes: float | Sequence[float] | None = None, + target_sizes: float | ArrayLike | None = None, recombine: bool = False, # noqa: FBT001, FBT002 ) -> pv.UnstructuredGrid | None: """ @@ -214,7 +215,7 @@ def frontal_delaunay_2d( # noqa: C901, PLR0912 (i.e. point ids are identical in the input and source). - target_sizes : float + target_sizes : float | ArrayLike Target mesh size close to the points. Default max size of edge_source in each direction. @@ -251,15 +252,11 @@ def frontal_delaunay_2d( # noqa: C901, PLR0912 target_sizes = [target_sizes] * (len(edge_source.interiors) + 1) for target_size, linearring in zip(target_sizes, [edge_source.exterior, *list(edge_source.interiors)]): - if isinstance(target_size, float): - target_size = [target_size] * (len(linearring.coords) - 1) - + sizes = [target_size] * (len(linearring.coords) - 1) if isinstance(target_size, float) else target_size coords = linearring.coords[:-1].copy() tags = [] - for size, coord in zip(target_size, coords): - x = coord[0] - y = coord[1] - z = coord[2] + for size, coord in zip(sizes, coords): + x, y, z = coord tags.append(gmsh.model.geo.add_point(x, y, z, size)) curve_tags = [] for i, _ in enumerate(tags): @@ -328,7 +325,7 @@ class Delaunay2D: A sequence of objects which satisfy the same requirements as the shell parameters above. - cell_size : float + cell_size : float | ArrayLike Meshing constraint at point. constrain_edge_size : bool @@ -346,7 +343,7 @@ def __init__( edge_source: pv.PolyData | shapely.Polygon | None = None, shell: Sequence[tuple[int]] | None = None, holes: Sequence[tuple[int]] | None = None, - cell_size: float | None = None, + cell_size: float | ArrayLike | None = None, constrain_edge_size: bool = False, ) -> None: """Initialize the Delaunay2D class.""" @@ -366,7 +363,7 @@ def __init__( line = lines[1 : lines[0] + 1] edge_points = edge_source.points[line] cell_size = self._compute_cell_size_from_points(edge_points) - + self._cell_size = cell_size @staticmethod @@ -374,7 +371,7 @@ def _compute_cell_size_from_points(points: ArrayLike) -> ArrayLike: """Compute cell size from points array.""" lengths = np.linalg.norm(np.diff(points, axis=0), axis=-1) lengths = np.insert(lengths, 0, lengths[-1]) - + return np.maximum(lengths[:-1], lengths[1:]) @property @@ -389,12 +386,12 @@ def mesh(self: Delaunay2D) -> pv.PolyData: return pv.PolyData(mesh.points, mesh.cells) @property - def cell_size(self: Delaunay2D) -> float | None: + def cell_size(self: Delaunay2D) -> float | ArrayLike | None: """Get the cell_size of the mesh.""" return self._cell_size @cell_size.setter - def cell_size(self: Delaunay2D, size: int) -> None: + def cell_size(self: Delaunay2D, size: float | ArrayLike | None) -> None: """Set the cell_size of the mesh.""" self._cell_size = size