diff --git a/src/engines_gpl/dflowfm/packages/dflowfm_kernel/src/dflowfm_kernel/prepost/find1dcells.f90 b/src/engines_gpl/dflowfm/packages/dflowfm_kernel/src/dflowfm_kernel/prepost/find1dcells.f90
index 8b7d9301df..4cbcad8b03 100644
--- a/src/engines_gpl/dflowfm/packages/dflowfm_kernel/src/dflowfm_kernel/prepost/find1dcells.f90
+++ b/src/engines_gpl/dflowfm/packages/dflowfm_kernel/src/dflowfm_kernel/prepost/find1dcells.f90
@@ -49,7 +49,8 @@ module m_find1dcells
!> it is assumed that kc has been allocated
!> it is assumed that findcells has already been called (for 2d cells)
subroutine find1dcells()
- use m_cellmask_from_polygon_set, only: init_cell_geom_as_polylines, point_find_netcell, cleanup_cell_geom_polylines
+ use m_cellmask_from_polygon_set, only: point_find_netcell, cleanup_cell_geom_polylines
+ use m_pol_to_cellmask, only: init_cell_geom_as_polylines
implicit none
diff --git a/src/engines_gpl/dflowfm/packages/dflowfm_kernel/src/dflowfm_kernel/prepost/m_pol_to_cellmask.F90 b/src/engines_gpl/dflowfm/packages/dflowfm_kernel/src/dflowfm_kernel/prepost/m_pol_to_cellmask.F90
new file mode 100644
index 0000000000..2891fab09e
--- /dev/null
+++ b/src/engines_gpl/dflowfm/packages/dflowfm_kernel/src/dflowfm_kernel/prepost/m_pol_to_cellmask.F90
@@ -0,0 +1,159 @@
+ !----- AGPL --------------------------------------------------------------------
+!
+! Copyright (C) Stichting Deltares, 2017-2026.
+!
+! This file is part of Delft3D (D-Flow Flexible Mesh component).
+!
+! Delft3D is free software: you can redistribute it and/or modify
+! it under the terms of the GNU Affero General Public License as
+! published by the Free Software Foundation version 3.
+!
+! Delft3D is distributed in the hope that it will be useful,
+! but WITHOUT ANY WARRANTY; without even the implied warranty of
+! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+! GNU Affero General Public License for more details.
+!
+! You should have received a copy of the GNU Affero General Public License
+! along with Delft3D. If not, see .
+!
+! contact: delft3d.support@deltares.nl
+! Stichting Deltares
+! P.O. Box 177
+! 2600 MH Delft, The Netherlands
+!
+! All indications and logos of, and references to, "Delft3D",
+! "D-Flow Flexible Mesh" and "Deltares" are registered trademarks of Stichting
+! Deltares, and remain the property of Stichting Deltares. All rights reserved.
+!
+!-------------------------------------------------------------------------------
+
+!> Wrapper around cellmask_from_polygon_set that uses OpenMP to parallelize the loop over all points if not in MPI mode
+module m_pol_to_cellmask
+ use precision, only: dp
+ use m_cellmask_from_polygon_set, only: cellmask_from_polygon_set_init, cellmask_from_polygon_set_cleanup, cellmask_from_polygon_set
+
+ implicit none
+
+ private
+
+ public :: pol_to_cellmask, init_cell_geom_as_polylines, find_cells_crossed_by_polyline
+
+
+contains
+
+ subroutine pol_to_cellmask()
+ use network_data, only: cellmask, nump1d2d, npl, nump, xzw, yzw, xpl, ypl, zpl
+ use m_alloc, only: realloc
+
+ integer :: k
+
+ if (NPL == 0) then
+ return
+ end if
+
+ call realloc(cellmask, nump1d2d, keepexisting=.false., fill=0)
+
+ call cellmask_from_polygon_set_init(NPL, xpl, ypl, zpl)
+
+ !> Dynamic scheduling in case of unequal work, chunksize guided
+ !$OMP PARALLEL DO SCHEDULE(GUIDED)
+ do k = 1, nump
+ cellmask(k) = cellmask_from_polygon_set(xzw(k), yzw(k))
+ end do
+ !$OMP END PARALLEL DO
+
+ call cellmask_from_polygon_set_cleanup()
+
+ end subroutine pol_to_cellmask
+
+!> Initialize xpl, ypl, zpl arrays with all netcell geometries (called once)
+ subroutine init_cell_geom_as_polylines()
+ use network_data
+ use m_alloc
+ USE m_cellmask_from_polygon_set, ONLY: cellmask_from_polygon_set_init, cellmask_initialized
+ use m_missing, only: dmiss
+
+ integer :: k, n, k1, total_points, ipoint
+
+ if (cellmask_initialized) then !> reuse cellmask cache boolean
+ return
+ end if
+
+ call savepol()
+
+ ! calculate total points needed: sum(netcell(k)%n + 1) for all cells
+ ! +1 for dmiss separator after each polygon
+ total_points = 0
+ do k = 1, nump
+ total_points = total_points + netcell(k)%n + 1 ! +1 for dmiss
+ end do
+
+ ! allocate or reallocate xpl, ypl, zpl
+ call realloc(xpl, total_points, keepexisting=.false.)
+ call realloc(ypl, total_points, keepexisting=.false.)
+ call realloc(zpl, total_points, keepexisting=.false.)
+
+ ! fill arrays with netcell geometry
+ ipoint = 0
+ do k = 1, nump
+ do n = 1, netcell(k)%n
+ ipoint = ipoint + 1
+ k1 = netcell(k)%nod(n)
+ xpl(ipoint) = xk(k1)
+ ypl(ipoint) = yk(k1)
+ zpl(ipoint) = real(k, dp) ! store cell index as z-value
+ end do
+
+ ! add separator
+ ipoint = ipoint + 1
+ xpl(ipoint) = dmiss
+ ypl(ipoint) = dmiss
+ zpl(ipoint) = dmiss
+ end do
+
+ npl = ipoint
+
+ ! initialize the cellmask module with these polygons
+ ! this builds bounding boxes and polygon indices
+ call cellmask_from_polygon_set_init(npl, xpl, ypl, zpl)
+
+ end subroutine init_cell_geom_as_polylines
+
+!> Find all cells crossed by polyline using brute force on cached geometry. The routine is inclusive of edge cases (touching edges or vertices).
+ subroutine find_cells_crossed_by_polyline(xpoly, ypoly, crossed_cells, error)
+ use m_alloc, only: realloc
+ use network_data, only: cellmask, nump
+ use m_missing, only: dmiss
+ use m_cellmask_from_polygon_set, only: cellmask_initialized, find_cells_for_segment
+
+ real(kind=dp), intent(in) :: xpoly(:) !< Polyline x-coordinates
+ real(kind=dp), intent(in) :: ypoly(:) !< Polyline y-coordinates
+ integer, allocatable, intent(out) :: crossed_cells(:) !> Indices of crossed cells in network_data::netcells
+ character, dimension(:), allocatable, intent(out) :: error !> Error message, empty if no error, to be handled at call site
+
+ integer :: npoly, i
+
+ error = ''
+
+ npoly = size(xpoly)
+ if (any(xpoly == dmiss) .or. any(ypoly == dmiss) .or. npoly < 2) then
+ error = 'Invalid polyline input'
+ return
+ end if
+
+ if (.not. cellmask_initialized) then
+ call init_cell_geom_as_polylines()
+ end if
+
+ call realloc(cellmask, nump, keepexisting=.false., fill=0)
+
+ ! Process each segment and put the result in cellmask
+ do i = 1, npoly - 1
+ call find_cells_for_segment(xpoly(i), ypoly(i), xpoly(i + 1), ypoly(i + 1), cellmask)
+ end do
+
+ crossed_cells = pack([(i, i=1, nump)], mask=(cellmask == 1))
+
+ end subroutine find_cells_crossed_by_polyline
+
+end module m_pol_to_cellmask
diff --git a/src/engines_gpl/dflowfm/packages/dflowfm_kernel/src/dflowfm_gui/m_samples_to_cellmask.f90 b/src/engines_gpl/dflowfm/packages/dflowfm_kernel/src/dflowfm_kernel/prepost/m_samples_to_cellmask.f90
similarity index 94%
rename from src/engines_gpl/dflowfm/packages/dflowfm_kernel/src/dflowfm_gui/m_samples_to_cellmask.f90
rename to src/engines_gpl/dflowfm/packages/dflowfm_kernel/src/dflowfm_kernel/prepost/m_samples_to_cellmask.f90
index cce9ce5c07..47ded9a5e0 100644
--- a/src/engines_gpl/dflowfm/packages/dflowfm_kernel/src/dflowfm_gui/m_samples_to_cellmask.f90
+++ b/src/engines_gpl/dflowfm/packages/dflowfm_kernel/src/dflowfm_kernel/prepost/m_samples_to_cellmask.f90
@@ -39,7 +39,8 @@ subroutine samples_to_cellmask()
use network_data, only: cellmask, nump1d2d
use m_samples, only: ns, xs, ys
- use m_cellmask_from_polygon_set, only: init_cell_geom_as_polylines, point_find_netcell, cleanup_cell_geom_polylines
+ use m_cellmask_from_polygon_set, only: point_find_netcell, cleanup_cell_geom_polylines
+ use m_pol_to_cellmask, only: init_cell_geom_as_polylines
use m_alloc, only: realloc
integer :: i, k
diff --git a/src/engines_gpl/dflowfm/packages/dflowfm_kernel/src/dflowfm_kernel/prepost/pol_to_cellmask.F90 b/src/engines_gpl/dflowfm/packages/dflowfm_kernel/src/dflowfm_kernel/prepost/pol_to_cellmask.F90
deleted file mode 100644
index 53aa7697dc..0000000000
--- a/src/engines_gpl/dflowfm/packages/dflowfm_kernel/src/dflowfm_kernel/prepost/pol_to_cellmask.F90
+++ /dev/null
@@ -1,68 +0,0 @@
- !----- AGPL --------------------------------------------------------------------
-!
-! Copyright (C) Stichting Deltares, 2017-2026.
-!
-! This file is part of Delft3D (D-Flow Flexible Mesh component).
-!
-! Delft3D is free software: you can redistribute it and/or modify
-! it under the terms of the GNU Affero General Public License as
-! published by the Free Software Foundation version 3.
-!
-! Delft3D is distributed in the hope that it will be useful,
-! but WITHOUT ANY WARRANTY; without even the implied warranty of
-! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-! GNU Affero General Public License for more details.
-!
-! You should have received a copy of the GNU Affero General Public License
-! along with Delft3D. If not, see .
-!
-! contact: delft3d.support@deltares.nl
-! Stichting Deltares
-! P.O. Box 177
-! 2600 MH Delft, The Netherlands
-!
-! All indications and logos of, and references to, "Delft3D",
-! "D-Flow Flexible Mesh" and "Deltares" are registered trademarks of Stichting
-! Deltares, and remain the property of Stichting Deltares. All rights reserved.
-!
-!-------------------------------------------------------------------------------
-
-!> Wrapper around cellmask_from_polygon_set that uses OpenMP to parallelize the loop over all points if not in MPI mode
-module m_pol_to_cellmask
- use precision, only: dp
- use m_cellmask_from_polygon_set, only: cellmask_from_polygon_set_init, cellmask_from_polygon_set_cleanup, cellmask_from_polygon_set
-
- implicit none
-
- private
-
- public :: pol_to_cellmask
-
-contains
-
- subroutine pol_to_cellmask()
- use network_data, only: cellmask, nump1d2d, npl, nump, xzw, yzw, xpl, ypl, zpl
- use m_alloc, only: realloc
-
- integer :: k
-
- if (NPL == 0) then
- return
- end if
-
- call realloc(cellmask, nump1d2d, keepexisting=.false., fill=0)
-
- call cellmask_from_polygon_set_init(NPL, xpl, ypl, zpl)
-
- !> Dynamic scheduling in case of unequal work, chunksize guided
- !$OMP PARALLEL DO SCHEDULE(GUIDED)
- do k = 1, nump
- cellmask(k) = cellmask_from_polygon_set(xzw(k), yzw(k))
- end do
- !$OMP END PARALLEL DO
-
- call cellmask_from_polygon_set_cleanup()
-
- end subroutine pol_to_cellmask
-
-end module m_pol_to_cellmask
diff --git a/src/engines_gpl/dflowfm/packages/dflowfm_kernel/src/dflowfm_kernel/timespace/fm_external_forcings.f90 b/src/engines_gpl/dflowfm/packages/dflowfm_kernel/src/dflowfm_kernel/timespace/fm_external_forcings.f90
index a5209cb350..0ab5d6b7a4 100644
--- a/src/engines_gpl/dflowfm/packages/dflowfm_kernel/src/dflowfm_kernel/timespace/fm_external_forcings.f90
+++ b/src/engines_gpl/dflowfm/packages/dflowfm_kernel/src/dflowfm_kernel/timespace/fm_external_forcings.f90
@@ -2509,7 +2509,8 @@ subroutine finalize()
use m_filez, only: doclose
use m_physcoef, only: constant_dicoww, dicoww
use m_array_or_scalar, only: realloc
- use m_cellmask_from_polygon_set, only: init_cell_geom_as_polylines, point_find_netcell, cleanup_cell_geom_polylines
+ use m_cellmask_from_polygon_set, only: point_find_netcell, cleanup_cell_geom_polylines
+ use m_pol_to_cellmask, only: init_cell_geom_as_polylines
integer :: j, k, ierr, l, n, itp, kk, k1, k2, kb, kt, nstor, i, ja
integer :: imba, needextramba, needextrambar
diff --git a/src/engines_gpl/dflowfm/packages/dflowfm_kernel/test/test_pol_to_cellmask.f90 b/src/engines_gpl/dflowfm/packages/dflowfm_kernel/test/test_pol_to_cellmask.f90
index 7db987e4a2..5f248c4276 100644
--- a/src/engines_gpl/dflowfm/packages/dflowfm_kernel/test/test_pol_to_cellmask.f90
+++ b/src/engines_gpl/dflowfm/packages/dflowfm_kernel/test/test_pol_to_cellmask.f90
@@ -3,7 +3,8 @@ module test_pol_to_cellmask
use precision, only: dp
use m_missing, only: dmiss
use network_data, only: cellmask, npl, nump, xzw, yzw, xpl, ypl, zpl
- use m_cellmask_from_polygon_set, only: cellmask_from_polygon_set_init, cellmask_from_polygon_set, cellmask_from_polygon_set_cleanup
+ use m_cellmask_from_polygon_set
+ use m_pol_to_cellmask
use geometry_module, only: pinpok_legacy, pinpok_raycast
implicit none(external)
@@ -406,7 +407,8 @@ end subroutine test_pinpok_raycast_complex
subroutine test_incells_basic_functionality() bind(C)
! Test basic incells functionality: point inside/outside netcells
use gridoperations, only: incells
- use m_cellmask_from_polygon_set, only: init_cell_geom_as_polylines, point_find_netcell, cleanup_cell_geom_polylines
+ use m_cellmask_from_polygon_set, only: point_find_netcell, cleanup_cell_geom_polylines
+ use m_pol_to_cellmask, only: init_cell_geom_as_polylines
use network_data, only: netcell, nump, xk, yk
use m_alloc, only: realloc
@@ -471,7 +473,8 @@ end subroutine test_incells_basic_functionality
subroutine test_incells_complex_geometry() bind(C)
! Test incells with more complex netcell geometries (triangles, pentagons, hexagons)
use gridoperations, only: incells
- use m_cellmask_from_polygon_set, only: init_cell_geom_as_polylines, point_find_netcell, cleanup_cell_geom_polylines
+ use m_cellmask_from_polygon_set, only: point_find_netcell, cleanup_cell_geom_polylines
+ use m_pol_to_cellmask, only: init_cell_geom_as_polylines
use network_data, only: netcell, nump, xk, yk
integer :: kin_old, kin_new
@@ -524,7 +527,8 @@ end subroutine test_incells_complex_geometry
subroutine test_incells_large_grid() bind(C)
! Test incells with a larger grid (performance sanity check)
use gridoperations, only: incells
- use m_cellmask_from_polygon_set, only: init_cell_geom_as_polylines, point_find_netcell, cleanup_cell_geom_polylines
+ use m_cellmask_from_polygon_set, only: point_find_netcell, cleanup_cell_geom_polylines
+ use m_pol_to_cellmask, only: init_cell_geom_as_polylines
use network_data, only: netcell, nump
integer :: kin_old, kin_new, i, mismatches
@@ -566,7 +570,8 @@ end subroutine test_incells_large_grid
subroutine test_incells_cache_consistency() bind(C)
! Test that cache initialization produces consistent results
use gridoperations, only: incells
- use m_cellmask_from_polygon_set, only: init_cell_geom_as_polylines, point_find_netcell, cleanup_cell_geom_polylines
+ use m_cellmask_from_polygon_set, only: point_find_netcell, cleanup_cell_geom_polylines
+ use m_pol_to_cellmask, only: init_cell_geom_as_polylines
use network_data, only: nump
integer :: kin1, kin2, kin_old
@@ -614,7 +619,8 @@ end subroutine test_incells_cache_consistency
subroutine test_incells_edge_cases() bind(C)
! Test edge cases: empty grid, single cell, point at infinity
use gridoperations, only: incells
- use m_cellmask_from_polygon_set, only: init_cell_geom_as_polylines, point_find_netcell, cleanup_cell_geom_polylines
+ use m_cellmask_from_polygon_set, only: point_find_netcell, cleanup_cell_geom_polylines
+ use m_pol_to_cellmask, only: init_cell_geom_as_polylines
use network_data, only: netcell, nump
integer :: kin_old, kin_new
@@ -819,7 +825,6 @@ end subroutine test_samples_to_cellmask_edge_cases
!$f90tw TESTCODE(TEST, test_pol_to_cellmask, test_find_cells_crossed_by_polyline_simple, test_find_cells_crossed_by_polyline_simple,
subroutine test_find_cells_crossed_by_polyline_simple() bind(C)
! Test find_cells_crossed_by_polyline: polyline crosses some cells, misses others
- use m_cellmask_from_polygon_set, only: init_cell_geom_as_polylines, find_cells_crossed_by_polyline, cleanup_cell_geom_polylines
use network_data, only: nump
use m_alloc, only: realloc
@@ -888,7 +893,6 @@ end subroutine test_find_cells_crossed_by_polyline_simple
!$f90tw TESTCODE(TEST, test_pol_to_cellmask, test_find_cells_crossed_by_polyline_edge_cases, test_find_cells_crossed_by_polyline_edge_cases,
subroutine test_find_cells_crossed_by_polyline_edge_cases() bind(C)
! Test find_cells_crossed_by_polyline: polyline crosses some cells, misses others
- use m_cellmask_from_polygon_set, only: init_cell_geom_as_polylines, find_cells_crossed_by_polyline, cleanup_cell_geom_polylines
use network_data, only: nump
use m_alloc, only: realloc
@@ -952,6 +956,50 @@ end subroutine test_find_cells_crossed_by_polyline_edge_cases
! Helper subroutines for setting up test geometries
! ============================================================================
+!$f90tw TESTCODE(TEST, test_pol_to_cellmask, test_dbpinpol_basic_functionality, test_dbpinpol_basic_functionality,
+ subroutine test_dbpinpol_basic_functionality() bind(C)
+ ! Test dbpinpol with known inputs/outputs (no legacy comparison)
+ use geometry_module, only: dbpinpol
+ use m_polygon, only: xpl, ypl, zpl, npl
+ use m_alloc, only: realloc
+
+ real(kind=dp) :: xp, yp
+ integer :: in_result
+
+ ! Setup simple rectangular polygon
+ npl = 5
+ call realloc(xpl, npl, keepexisting=.false.)
+ call realloc(ypl, npl, keepexisting=.false.)
+ call realloc(zpl, npl, keepexisting=.false.)
+
+ xpl = [0.0_dp, 10.0_dp, 10.0_dp, 0.0_dp, 0.0_dp]
+ ypl = [0.0_dp, 0.0_dp, 10.0_dp, 10.0_dp, 0.0_dp]
+ zpl = [1.0_dp, 1.0_dp, 1.0_dp, 1.0_dp, 1.0_dp]
+
+ ! Initialize AND test first point
+ in_result = -1
+ xp = 0.0_dp
+ yp = 0.0_dp
+ call dbpinpol(xp, yp, in_result, dmiss, 1, npl, xpl, ypl, zpl)
+ call f90_expect_eq(in_result, 1, "Point (0,0) should be inside polygon")
+
+ ! Test second point (reusing cached data)
+ xp = 5.0_dp
+ yp = 5.0_dp
+ call dbpinpol(xp, yp, in_result, dmiss, 1, npl, xpl, ypl, zpl)
+ call f90_expect_eq(in_result, 1, "Point (5,5) should be inside polygon")
+
+ ! Test outside point
+ xp = 15.0_dp
+ yp = 15.0_dp
+ call dbpinpol(xp, yp, in_result, dmiss, 1, npl, xpl, ypl, zpl)
+ call f90_expect_eq(in_result, 0, "Point (15,15) should be outside polygon")
+
+ deallocate (xpl, ypl, zpl)
+
+ end subroutine
+!$f90tw)
+
! Helper subroutine: setup 5 cells in a row (0-10, 10-20, 20-30, 30-40, 40-50)
subroutine setup_row_netcells()
use network_data, only: netcell, nump, xk, yk, numk, nump1d2d
diff --git a/src/utils_lgpl/deltares_common/packages/deltares_common/src/geometry_module.f90 b/src/utils_lgpl/deltares_common/packages/deltares_common/src/geometry_module.f90
index c6171c35f2..63bea731ea 100644
--- a/src/utils_lgpl/deltares_common/packages/deltares_common/src/geometry_module.f90
+++ b/src/utils_lgpl/deltares_common/packages/deltares_common/src/geometry_module.f90
@@ -61,7 +61,6 @@ module geometry_module
public :: cart3Dtospher
public :: dbpinpol
public :: cross
- public :: dbpinpol_optinside_perpol
public :: get_startend
public :: pinpok3D
public :: cross3D
@@ -101,6 +100,17 @@ module geometry_module
module procedure clockwise_hp
end interface clockwise
+ ! Interface for dbpinpol (implementation in submodule)
+ interface
+ module subroutine dbpinpol(xp, yp, in, dmiss, JINS, NPL, xpl, ypl, zpl)
+ real(kind=dp), intent(in) :: xp, yp
+ integer, intent(inout) :: in
+ real(kind=dp), intent(in) :: dmiss
+ integer, intent(in) :: JINS, NPL
+ real(kind=dp), optional, intent(in) :: xpl(:), ypl(:), zpl(:)
+ end subroutine dbpinpol
+ end interface
+
contains
!> projects a point to a polyline and finds the closest link.
@@ -275,76 +285,69 @@ pure subroutine pinpok(xl, yl, n, x, y, inside, jins_dummy, dmiss_dummy)
!> optimized ray-casting point-in-polygon test.
!! pure function that works with array slices or full arrays.
- pure function pinpok_raycast(xl, yl, x, y, n) result(is_inside)
+pure function pinpok_raycast(xl, yl, x, y, n) result(is_inside)
- real(kind=dp), intent(in) :: xl, yl !< point coordinates to test
- integer, intent(in) :: n !< number of polygon points
- real(kind=dp), dimension(n), intent(in) :: x, y !< polygon coordinates (at least n elements)
- logical :: is_inside !< result: true if inside (respecting jins mode)
+ real(kind=dp), intent(in) :: xl, yl !< point coordinates to test
+ integer, intent(in) :: n !< number of polygon points
+ real(kind=dp), dimension(n), intent(in) :: x, y !< polygon coordinates (at least n elements)
+ logical :: is_inside !< result: true if inside (respecting jins mode)
- ! locals
- integer :: i, j, crossings
- real(kind=dp) :: x_intersect
+ ! locals
+ integer :: i, j, crossings
+ real(kind=dp) :: x_intersect
+ real(kind=dp), parameter :: edge_tolerance = 1.0e-10_dp
- is_inside = .false.
+ is_inside = .false.
- ! degenerate polygon check
- if (n <= 2) then
- is_inside = .true.
- if (jins == 0) then
+ ! degenerate polygon check
+ if (n <= 2) then
+ is_inside = .true.
+ if (jins == 0) then
is_inside = .not. is_inside
- end if
- return
- end if
+ end if
+ return
+ end if
- ! ray-casting algorithm: count crossings of horizontal ray from point to +infinity
- crossings = 0
+ ! ray-casting algorithm: count crossings of horizontal ray from point to +infinity
+ crossings = 0
j = n ! In order to check the entire polygon, start the first link which lies between the last point (n) and the first point
- do i = 1, n
- ! check for missing value (polygon separator)
- if (x(i) == dmiss) then
+ do i = 1, n
+ ! check for missing value (polygon separator)
+ if (x(i) == dmiss) then
exit
- end if
-
- ! check if point is exactly on a vertex
- if (xl == x(j) .and. yl == y(j)) then
- is_inside = .true.
- if (jins == 0) then
- is_inside = .not. is_inside
- end if
- return
- end if
+ end if
- ! check if ray crosses this edge
- ! edge crosses horizontal line through test point if one endpoint is above and one below
- if ((y(j) > yl) .neqv. (y(i) > yl)) then
+ ! check if ray crosses this edge
+ ! edge crosses horizontal line through test point if one endpoint is above and one below
+ if ((y(j) > yl) .neqv. (y(i) > yl)) then
! compute x-coordinate of edge-ray intersection
x_intersect = x(j) + (yl - y(j)) * (x(i) - x(j)) / (y(i) - y(j))
- if (xl < x_intersect) then
- ! ray crosses edge to the right of point
- crossings = crossings + 1
- else if (xl == x_intersect) then
- ! point is exactly on the edge
- is_inside = .true.
- if (jins == 0) then
- is_inside = .not. is_inside
- end if
- return
+
+ if (xl < x_intersect - edge_tolerance) then
+ ! ray crosses edge to the right of point
+ crossings = crossings + 1
+ else if (abs(xl - x_intersect) <= edge_tolerance) then
+ ! point is on or very near the edge (including vertices)
+ is_inside = .true.
+ if (jins == 0) then
+ is_inside = .not. is_inside
+ end if
+ return
end if
- end if
+ end if
j = i ! current point becomes previous for next iteration
- end do
+ end do
- ! odd number of crossings = inside, even = outside
- is_inside = (mod(crossings, 2) == 1)
+ ! odd number of crossings = inside, even = outside
+ is_inside = (mod(crossings, 2) == 1)
- ! respect jins mode
- if (jins == 0) then
- is_inside = .not. is_inside
- end if
+ ! respect jins mode
+ if (jins == 0) then
+ is_inside = .not. is_inside
+ end if
- end function pinpok_raycast
+end function pinpok_raycast
!
! PINPOK
!
@@ -865,182 +868,6 @@ function matprod(A, b)
matprod = (/(A(i, 1) * b(1) + A(i, 2) * b(2) + A(i, 3) * b(3), i=1, 3)/)
end function matprod
- subroutine dbpinpol(xp, yp, in, dmiss, JINS, NPL, xpl, ypl, zpl) ! ALS JE VOOR VEEL PUNTEN MOET NAGAAN OF ZE IN POLYGON ZITTEN
- implicit none
- real(kind=dp), intent(in) :: xp, yp !< point coordinates
- integer, intent(inout) :: in !< in(-1): initialization, out(0): outside polygon, out(1): inside polygon
- integer :: num
- real(kind=dp), intent(in) :: dmiss
- integer, intent(in) :: JINS, NPL
- real(kind=dp), optional, intent(in) :: xpl(:), ypl(:), zpl(:)
-
- if (NPL > 0 .and. present(xpl)) then
- call dbpinpol_optinside_perpol(xp, yp, 0, 0, in, num, dmiss, JINS, NPL, xpl, ypl, zpl)
- else
- call dbpinpol_optinside_perpol(xp, yp, 0, 0, in, num, dmiss, JINS, NPL)
- end if
- end subroutine dbpinpol
-
- !> The original dbpinpol routine, extended with an optional per-polygon-specified inside-mode.
- !! Used this for checking for many points whether they are inside the global polygons.
- !! Optionally, the global jins=1/other:inside/outside-mode can be replaced by an
- !! inside/outside mode per polygon: that should then be stored as a +1/-1 in the first
- !! zpl(istart) point of each polygon.
- subroutine dbpinpol_optinside_perpol(xp, yp, inside_perpol, iselect, in, numselect, dmiss, JINS, NPL, xpl, ypl, zpl) ! ALS JE VOOR VEEL PUNTEN MOET NAGAAN OF ZE IN POLYGON ZITTEN
-
- use m_alloc
-
- implicit none
-
- real(kind=dp), intent(in) :: xp, yp !< point coordinates
- integer, intent(in) :: inside_perpol !< Specify whether or not (1/0) to use each polygon's first point zpl-value as the jins(ide)-option (only 0 or 1 allowed), or use the global JINS variable.
- integer, intent(in) :: iselect !< use all polygons (0), only first-zpl<0 polygons (-1), or all but first-zpl<0 polygons (1)
- integer, intent(inout) :: in !< in(-1): initialization, out(0): outside polygon, out(1): inside polygon
- integer, intent(inout) :: numselect !< number of polygons of "iselect" type considered
-
- integer :: MAXPOLY = 1000 ! will grow if needed
-
- real(kind=dp), allocatable, save :: xpmin(:), ypmin(:), xpmax(:), ypmax(:)
- integer, save :: Npoly
- integer, allocatable, save :: iistart(:), iiend(:)
-
- integer :: ipoint ! points to first part of a polygon-subsection in polygon array
- integer :: istart, iend ! point to start and and node of a polygon in polygon array respectively
- integer :: ipoly ! polygon number
-
- logical :: Linit ! initialization of polygon bounds, and start and end nodes respectively
-
- integer :: jins_opt !< The actual used jins-mode (either global, or per poly)
- real(kind=dp), intent(in) :: dmiss
- integer, intent(in) :: JINS, NPL
- real(kind=dp), optional, intent(in) :: xpl(NPL), ypl(NPL), zpl(NPL)
- integer :: count
- numselect = 0
-
- if (NPL == 0) then
- in = 1
- return
- end if
-
- Linit = (in < 0)
-
- in = 0
-
- ! initialization
- if (Linit) then
- ! write(6,"('dbpinpol: init... ', $)")
- ipoint = 1
- ipoly = 0
- call realloc(xpmin, maxpoly, keepExisting=.false.)
- call realloc(xpmax, maxpoly, keepExisting=.false.)
- call realloc(ypmin, maxpoly, keepExisting=.false.)
- call realloc(ypmax, maxpoly, keepExisting=.false.)
- call realloc(iistart, maxpoly, keepExisting=.false.)
- call realloc(iiend, maxpoly, keepExisting=.false.)
-
- do while (ipoint < NPL)
- ipoly = ipoly + 1
- if (ipoly > maxpoly) then
- maxpoly = ceiling(maxpoly * 1.1)
- call realloc(xpmin, maxpoly, keepExisting=.true.)
- call realloc(xpmax, maxpoly, keepExisting=.true.)
- call realloc(ypmin, maxpoly, keepExisting=.true.)
- call realloc(ypmax, maxpoly, keepExisting=.true.)
- call realloc(iistart, maxpoly, keepExisting=.true.)
- call realloc(iiend, maxpoly, keepExisting=.true.)
- end if
-
- ! get polygon start and end pointer respectively
- call get_startend(NPL - ipoint + 1, xpl(ipoint:NPL), ypl(ipoint:NPL), istart, iend, dmiss)
- istart = istart + ipoint - 1
- iend = iend + ipoint - 1
-
- if (istart >= iend .or. iend > NPL) exit ! done
-
- xpmin(ipoly) = minval(xpl(istart:iend))
- xpmax(ipoly) = maxval(xpl(istart:iend))
- ypmin(ipoly) = minval(ypl(istart:iend))
- ypmax(ipoly) = maxval(ypl(istart:iend))
-
- iistart(ipoly) = istart
- iiend(ipoly) = iend
-
- ! advance pointer
- ipoint = iend + 2
- end do ! do while ( ipoint < NPL .and. ipoly < MAXPOLY )
- Npoly = ipoly
-
- ! write(6,"('done, Npoly=', I4)") Npoly
- end if
- count = 0
- do ipoly = 1, Npoly
- istart = iistart(ipoly)
- iend = iiend(ipoly)
-
- ! write(6,"('dbpinpol: ipoly=', I4, ', istart=', I16, ', iend=', I16)") ipoly, istart, iend
-
- if (istart >= iend .or. iend > NPL) exit ! done
-
- if (iselect == -1 .and. (zpl(istart) == DMISS .or. zpl(istart) >= 0)) cycle
- if (iselect == 1 .and. (zpl(istart) /= DMISS .and. zpl(istart) < 0)) cycle
-
- numselect = numselect + 1
-
- if (inside_perpol == 1 .and. zpl(istart) /= dmiss) then ! only if third column was actually supplied
- jins_opt = int(zpl(istart)) ! Use inside-option per each polygon.
- else
- jins_opt = JINS ! Use global inside-option.
- end if
-
- if (jins_opt == 1) then ! inside polygon
- if (xp >= xpmin(ipoly) .and. xp <= xpmax(ipoly) .and. &
- yp >= ypmin(ipoly) .and. yp <= ypmax(ipoly)) then
- call PINPOK(Xp, Yp, iend - istart + 1, xpl(istart), ypl(istart), IN, jins, dmiss)
- if (jins_opt > 0 .neqv. JINS > 0) then ! PINPOK has used global jins, but polygon asked the exact opposite, so negate the result here.
- IN = 1 - in ! IN-1
- end if
-
- if (in == 1) then
- count = count + 1
- end if
- end if
- else ! outside polygon
- if (xp >= xpmin(ipoly) .and. xp <= xpmax(ipoly) .and. &
- yp >= ypmin(ipoly) .and. yp <= ypmax(ipoly)) then
- call PINPOK(Xp, Yp, iend - istart + 1, xpl(istart), ypl(istart), IN, jins, dmiss)
- if (jins_opt > 0 .neqv. JINS > 0) then ! PINPOK has used global jins, but polygon asked the exact opposite, so negate the result here.
- IN = 1 - in ! IN-1
- end if
-
- if (in == 1) then
- continue
- else
- count = count + 1
- end if
- !else
- ! in = 1 ! outside check succeeded (completely outside of polygon's bounding box), return 'true'.
- ! exit
- end if
- end if
- end do ! do ipoly=1,Npoly
-
- if (jins == 1) then !< NB: here, it is checked based on jins, while in the loop based on jins_opt, need to be fixed
- if (mod(count, 2) == 1) then
- in = 1
- else
- in = 0
- end if
- else
- if (mod(count, 2) == 1) then
- in = 0
- else
- in = 1
- end if
- end if
-
- return
- end subroutine dbpinpol_optinside_perpol
-
!> get the start and end index of the first enclosed non-DMISS subarray
subroutine get_startend(num, x, y, jstart, jend, dmiss)
diff --git a/src/utils_lgpl/deltares_common/packages/deltares_common/src/geometry_module_dbpinpol.f90 b/src/utils_lgpl/deltares_common/packages/deltares_common/src/geometry_module_dbpinpol.f90
new file mode 100644
index 0000000000..a1abc2854d
--- /dev/null
+++ b/src/utils_lgpl/deltares_common/packages/deltares_common/src/geometry_module_dbpinpol.f90
@@ -0,0 +1,83 @@
+!----- LGPL --------------------------------------------------------------------
+!
+! Copyright (C) Stichting Deltares, 2011-2026.
+!
+! This library is free software; you can redistribute it and/or
+! modify it under the terms of the GNU Lesser General Public
+! License as published by the Free Software Foundation version 2.1.
+!
+! This library is distributed in the hope that it will be useful,
+! but WITHOUT ANY WARRANTY; without even the implied warranty of
+! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+! Lesser General Public License for more details.
+!
+! You should have received a copy of the GNU Lesser General Public
+! License along with this library; if not, see .
+!
+! contact: delft3d.support@deltares.nl
+! Stichting Deltares
+! P.O. Box 177
+! 2600 MH Delft, The Netherlands
+!
+! All indications and logos of, and references to, "Delft3D" and "Deltares"
+! are registered trademarks of Stichting Deltares, and remain the property of
+! Stichting Deltares. All rights reserved.
+!
+!-------------------------------------------------------------------------------
+!
+submodule (geometry_module) geometry_module_dbpinpol
+
+ implicit none
+
+contains
+
+ module subroutine dbpinpol(xp, yp, in, dmiss, JINS, NPL, xpl, ypl, zpl)
+ use m_cellmask_from_polygon_set, only: cellmask_from_polygon_set_init, &
+ cellmask_from_polygon_set, &
+ cellmask_from_polygon_set_cleanup
+ implicit none
+
+ real(kind=dp), intent(in) :: xp, yp
+ integer, intent(inout) :: in
+ real(kind=dp), intent(in) :: dmiss
+ integer, intent(in) :: JINS, NPL
+ real(kind=dp), optional, intent(in) :: xpl(:), ypl(:), zpl(:)
+
+ integer :: num
+ logical, save :: initialized = .false.
+
+ ! Special case: NPL == 0 means "no polygons to check, everything is considered inside"
+ if (NPL == 0) then
+ in = 1
+ return
+ end if
+
+ ! Initialization phase (when in < 0)
+ if (in < 0) then
+ ! Clean up any previous initialization
+ if (initialized) then
+ call cellmask_from_polygon_set_cleanup()
+ end if
+
+ ! Build optimized spatial index
+ if (present(xpl)) then
+ call cellmask_from_polygon_set_init(NPL, xpl, ypl, zpl)
+ initialized = .true.
+ end if
+
+ in = 0 ! Reset for subsequent queries
+ end if
+
+ ! Query phase (when in >= 0)
+ if (.not. initialized) then
+ ! Safety: if someone forgot to initialize
+ in = 0
+ return
+ end if
+
+ ! Use your optimized point-in-polygon with bounding boxes
+ in = cellmask_from_polygon_set(xp, yp)
+
+ end subroutine dbpinpol
+
+end submodule geometry_module_dbpinpol
\ No newline at end of file
diff --git a/src/engines_gpl/dflowfm/packages/dflowfm_kernel/src/dflowfm_kernel/prepost/m_cellmask_from_polygon_set.f90 b/src/utils_lgpl/deltares_common/packages/deltares_common/src/m_cellmask_from_polygon_set.f90
similarity index 82%
rename from src/engines_gpl/dflowfm/packages/dflowfm_kernel/src/dflowfm_kernel/prepost/m_cellmask_from_polygon_set.f90
rename to src/utils_lgpl/deltares_common/packages/deltares_common/src/m_cellmask_from_polygon_set.f90
index 35c5bce6ff..c13ddf055d 100644
--- a/src/engines_gpl/dflowfm/packages/dflowfm_kernel/src/dflowfm_kernel/prepost/m_cellmask_from_polygon_set.f90
+++ b/src/utils_lgpl/deltares_common/packages/deltares_common/src/m_cellmask_from_polygon_set.f90
@@ -32,13 +32,14 @@ module m_cellmask_from_polygon_set
use precision, only: dp
use m_polygon, only: xpl, ypl, zpl, npl, maxpol, restorepol, savepol
- implicit none
+ implicit none(external)
private
public :: cellmask_from_polygon_set_init, cellmask_from_polygon_set_cleanup, cellmask_from_polygon_set, pinpok_elemental
- public :: init_cell_geom_as_polylines, point_find_netcell, cleanup_cell_geom_polylines
- public :: find_cells_crossed_by_polyline
+ public :: point_find_netcell, cleanup_cell_geom_polylines
+ public :: cellmask_initialized
+ public :: find_cells_for_segment, line_segments_intersect, point_to_line_distance
integer :: polygons = 0 !< Number of polygons stored in module arrays xpl, ypl, zpl
real(kind=dp), allocatable :: x_poly_min(:), y_poly_min(:) !< Polygon bounding box min coordinates, (dim = polygons)
@@ -242,57 +243,6 @@ elemental function pinpok_elemental(x, y, i_poly) result(is_inside)
end function pinpok_elemental
- !> Initialize xpl, ypl, zpl arrays with all netcell geometries (called once)
- subroutine init_cell_geom_as_polylines()
- use network_data
- use m_alloc
-
- integer :: k, n, k1, total_points, ipoint
-
- if (cellmask_initialized) then !> reuse cellmask cache boolean
- return
- end if
-
- call savepol()
-
- ! calculate total points needed: sum(netcell(k)%n + 1) for all cells
- ! +1 for dmiss separator after each polygon
- total_points = 0
- do k = 1, nump
- total_points = total_points + netcell(k)%n + 1 ! +1 for dmiss
- end do
-
- ! allocate or reallocate xpl, ypl, zpl
- call realloc(xpl, total_points, keepexisting=.false.)
- call realloc(ypl, total_points, keepexisting=.false.)
- call realloc(zpl, total_points, keepexisting=.false.)
-
- ! fill arrays with netcell geometry
- ipoint = 0
- do k = 1, nump
- do n = 1, netcell(k)%n
- ipoint = ipoint + 1
- k1 = netcell(k)%nod(n)
- xpl(ipoint) = xk(k1)
- ypl(ipoint) = yk(k1)
- zpl(ipoint) = real(k, dp) ! store cell index as z-value
- end do
-
- ! add separator
- ipoint = ipoint + 1
- xpl(ipoint) = dmiss
- ypl(ipoint) = dmiss
- zpl(ipoint) = dmiss
- end do
-
- npl = ipoint
-
- ! initialize the cellmask module with these polygons
- ! this builds bounding boxes and polygon indices
- call cellmask_from_polygon_set_init(npl, xpl, ypl, zpl)
-
- end subroutine init_cell_geom_as_polylines
-
!> call general polygon cleanup and restore previous polygon data
subroutine cleanup_cell_geom_polylines()
call cellmask_from_polygon_set_cleanup()
@@ -333,50 +283,10 @@ elemental function point_find_netcell(x, y) result(k)
end function point_find_netcell
-!> Find all cells crossed by polyline using brute force on cached geometry. The routine is inclusive of edge cases (touching edges or vertices).
- subroutine find_cells_crossed_by_polyline(xpoly, ypoly, crossed_cells, error)
- use m_alloc, only: realloc
- use network_data, only: cellmask, nump
- use m_missing, only: dmiss
-
- implicit none
-
- real(kind=dp), intent(in) :: xpoly(:) !< Polyline x-coordinates
- real(kind=dp), intent(in) :: ypoly(:) !< Polyline y-coordinates
- integer, allocatable, intent(out) :: crossed_cells(:) !> Indices of crossed cells in network_data::netcells
- character, dimension(:), allocatable, intent(out) :: error !> Error message, empty if no error, to be handled at call site
-
- integer :: npoly, i
-
- error = ''
-
- npoly = size(xpoly)
- if (any(xpoly == dmiss) .or. any(ypoly == dmiss) .or. npoly < 2) then
- error = 'Invalid polyline input'
- return
- end if
-
- if (.not. cellmask_initialized) then
- call init_cell_geom_as_polylines()
- end if
-
- call realloc(cellmask, nump, keepexisting=.false., fill=0)
-
- ! Process each segment and put the result in cellmask
- do i = 1, npoly - 1
- call find_cells_for_segment(xpoly(i), ypoly(i), xpoly(i + 1), ypoly(i + 1), cellmask)
- end do
-
- crossed_cells = pack([(i, i=1, nump)], mask=(cellmask == 1))
-
- end subroutine find_cells_crossed_by_polyline
-
!> Find all cells that a segment crosses and mark them in cellmask
subroutine find_cells_for_segment(xa, ya, xb, yb, cellmask)
use m_polygon, only: xpl, ypl
- implicit none
-
real(kind=dp), intent(in) :: xa, ya, xb, yb !< Segment endpoints
integer, intent(inout) :: cellmask(:) !< Cell mask array: 1=crossed, 0=not crossed
diff --git a/src/utils_lgpl/deltares_common/packages/deltares_common/src/m_polygon.f90 b/src/utils_lgpl/deltares_common/packages/deltares_common/src/m_polygon.f90
new file mode 100644
index 0000000000..bbb7533a7c
--- /dev/null
+++ b/src/utils_lgpl/deltares_common/packages/deltares_common/src/m_polygon.f90
@@ -0,0 +1,155 @@
+module m_polygon
+
+ implicit none
+
+ double precision, allocatable :: XPL(:), YPL(:), ZPL(:), DZL(:), DZR(:), DCREST(:), DTL(:), DTR(:), DVEG(:)
+ double precision, allocatable, private :: XPH(:), YPH(:), ZPH(:)
+ integer, allocatable :: IWEIRT(:)
+ integer :: NPL, NPH, MAXPOL, MP, MPS, jakol45 = 0
+ character(len=64), allocatable :: nampli(:) ! Names of polylines, set in reapol,
+ ! not shifted/updated during editpol.
+ double precision :: dxuni = 40d0 ! uniform spacing
+ integer :: MAXPOLY = 1000 ! will grow if needed
+ double precision, allocatable :: xpmin(:), ypmin(:), xpmax(:), ypmax(:), zpmin(:), zpmax(:)
+ integer :: Npoly
+ integer, allocatable :: iistart(:), iiend(:)
+ integer, allocatable :: ipsection(:)
+
+contains
+ !> Increase size of global polyline array.
+ !! Specify new size and whether existing points need to be maintained.
+ subroutine increasepol(N, jaKeepExisting)
+ use m_missing
+ use m_alloc
+ implicit none
+ integer :: n !< Desired new minimum size
+ integer :: jaKeepExisting !< Whether or not (1/0) to keep existing points.
+ logical :: jakeep
+ integer :: maxpolcur
+ integer :: ierr
+
+ maxpolcur = size(xpl)
+ if (N <= maxpolcur) then
+ return
+ end if
+ MAXPOL = max(100000, int(5d0 * N))
+
+ jakeep = jaKeepExisting == 1
+
+ call realloc(xpl, maxpol, keepExisting=jakeep, fill=dxymis, stat=ierr)
+ call realloc(ypl, maxpol, keepExisting=jakeep, fill=dxymis, stat=ierr)
+ call realloc(zpl, maxpol, keepExisting=jakeep, fill=dxymis, stat=ierr)
+
+ if (jakol45 == 1) then
+ call realloc(dzl, maxpol, keepExisting=jakeep, fill=dxymis, stat=ierr)
+ call realloc(dzr, maxpol, keepExisting=jakeep, fill=dxymis, stat=ierr)
+ else if (jakol45 == 2) then
+ call realloc(dcrest, maxpol, keepExisting=jakeep, fill=dxymis, stat=ierr)
+ call realloc(dzl, maxpol, keepExisting=jakeep, fill=dxymis, stat=ierr)
+ call realloc(dzr, maxpol, keepExisting=jakeep, fill=dxymis, stat=ierr)
+ call realloc(dtl, maxpol, keepExisting=jakeep, fill=dxymis, stat=ierr)
+ call realloc(dtr, maxpol, keepExisting=jakeep, fill=dxymis, stat=ierr)
+ call realloc(dveg, maxpol, keepExisting=jakeep, fill=dxymis, stat=ierr)
+ call realloc(iweirt, maxpol, keepExisting=jakeep, stat=ierr)
+ end if
+
+ ! make sure nampli is allocated
+ if (.not. allocated(nampli)) then
+ allocate (nampli(0))
+ end if
+
+ end subroutine increasepol
+
+ !> Copies the global polygon into the backup polygon arrays.
+ subroutine SAVEPOL()
+
+ use m_alloc
+ use m_missing
+ implicit none
+
+ if (NPL > 0) then
+ call realloc(xph, maxpol, keepExisting=.false.)
+ call realloc(yph, maxpol, keepExisting=.false.)
+ call realloc(zph, maxpol, keepExisting=.false.)
+ XPH(1:NPL) = XPL(1:NPL)
+ YPH(1:NPL) = YPL(1:NPL)
+ ZPH(1:NPL) = ZPL(1:NPL)
+ end if
+
+ MPS = MP
+ NPH = NPL
+
+ return
+ end subroutine savepol
+
+ !> Puts back a previously saved backup polygon into the global polygon arrays.
+ subroutine RESTOREPOL()
+ use m_alloc
+ use m_missing
+ implicit none
+
+ maxpol = max(maxpol, nph)
+ call realloc(xpl, maxpol, keepExisting=.false.)
+ call realloc(ypl, maxpol, keepExisting=.false.)
+ call realloc(zpl, maxpol, keepExisting=.false.)
+
+ if (NPH > 0) then
+ XPL(1:NPH) = XPH(1:NPH)
+ YPL(1:NPH) = YPH(1:NPH)
+ ZPL(1:NPH) = ZPH(1:NPH)
+ deallocate (XPH, YPH, ZPH)
+ end if
+ MP = MPS
+ NPL = NPH
+
+ return
+ end subroutine restorepol
+
+ function m_polygon_destructor() result(ierr)
+
+ implicit none
+
+ integer :: ierr
+
+ ierr = 0
+
+ if (allocated(XPL) .and. ierr == 0) deallocate (XPL, stat=ierr)
+ if (allocated(YPL) .and. ierr == 0) deallocate (YPL, stat=ierr)
+ if (allocated(ZPL) .and. ierr == 0) deallocate (ZPL, stat=ierr)
+ if (allocated(XPH) .and. ierr == 0) deallocate (XPH, stat=ierr)
+
+ if (allocated(YPH) .and. ierr == 0) deallocate (YPH, stat=ierr)
+ if (allocated(ZPH) .and. ierr == 0) deallocate (ZPH, stat=ierr)
+ if (allocated(ZPH) .and. ierr == 0) deallocate (ZPH, stat=ierr)
+
+ if (allocated(DZL) .and. ierr == 0) deallocate (DZL, stat=ierr)
+ if (allocated(DZR) .and. ierr == 0) deallocate (DZR, stat=ierr)
+ if (allocated(DCREST) .and. ierr == 0) deallocate (DCREST, stat=ierr)
+ if (allocated(DTL) .and. ierr == 0) deallocate (DTL, stat=ierr)
+ if (allocated(DTR) .and. ierr == 0) deallocate (DTR, stat=ierr)
+ if (allocated(DVEG) .and. ierr == 0) deallocate (DVEG, stat=ierr)
+ if (allocated(IWEIRT) .and. ierr == 0) deallocate (IWEIRT, stat=ierr)
+
+ if (allocated(xpmin) .and. ierr == 0) deallocate (xpmin, stat=ierr)
+ if (allocated(ypmin) .and. ierr == 0) deallocate (ypmin, stat=ierr)
+ if (allocated(xpmax) .and. ierr == 0) deallocate (xpmax, stat=ierr)
+ if (allocated(ypmax) .and. ierr == 0) deallocate (ypmax, stat=ierr)
+ if (allocated(zpmin) .and. ierr == 0) deallocate (zpmin, stat=ierr)
+ if (allocated(zpmax) .and. ierr == 0) deallocate (zpmax, stat=ierr)
+ if (allocated(iistart) .and. ierr == 0) deallocate (iistart, stat=ierr)
+ if (allocated(iiend) .and. ierr == 0) deallocate (iiend, stat=ierr)
+ if (allocated(ipsection) .and. ierr == 0) deallocate (ipsection, stat=ierr)
+
+ jakol45 = 0
+ dxuni = 40d0
+ MAXPOLY = 1000
+ NPL = 0
+ NPH = 0
+ MAXPOL = 0
+ MP = 0
+ MPS = 0
+ Npoly = 0
+
+ end function m_polygon_destructor
+
+end module m_polygon
diff --git a/src/utils_lgpl/gridgeom/packages/gridgeom/src/generalmodules.f90 b/src/utils_lgpl/gridgeom/packages/gridgeom/src/generalmodules.f90
index 0b8eaea174..69d6da4e31 100644
--- a/src/utils_lgpl/gridgeom/packages/gridgeom/src/generalmodules.f90
+++ b/src/utils_lgpl/gridgeom/packages/gridgeom/src/generalmodules.f90
@@ -99,185 +99,6 @@ subroutine default_sferic()
end subroutine default_sferic
end module m_sferic
-module m_polygon
- use precision, only: dp
-
- implicit none
-
- real(kind=dp), allocatable, dimension(:) :: xpl
- real(kind=dp), allocatable, dimension(:) :: ypl
- real(kind=dp), allocatable, dimension(:) :: zpl
- real(kind=dp), allocatable, dimension(:) :: dzl
- real(kind=dp), allocatable, dimension(:) :: dzr
- real(kind=dp), allocatable, dimension(:) :: dcrest
- real(kind=dp), allocatable, dimension(:) :: dtl
- real(kind=dp), allocatable, dimension(:) :: dtr
- real(kind=dp), allocatable, dimension(:) :: dveg
- real(kind=dp), allocatable, dimension(:), private :: xph
- real(kind=dp), allocatable, dimension(:), private :: yph
- real(kind=dp), allocatable, dimension(:), private :: zph
- integer, allocatable, dimension(:) :: iweirt
- integer :: npl
- integer :: nph
- integer :: maxpol
- integer :: mp
- integer :: mps
- integer :: jakol45 = 0
- character(len=64), allocatable, dimension(:) :: nampli ! Names of polylines, set in reapol,
-
- ! not shifted/updated during editpol.
- real(kind=dp) :: dxuni = 40d0 ! uniform spacing
- integer :: maxpoly = 1000 ! will grow if needed
- real(kind=dp), allocatable, dimension(:) :: xpmin
- real(kind=dp), allocatable, dimension(:) :: ypmin
- real(kind=dp), allocatable, dimension(:) :: xpmax
- real(kind=dp), allocatable, dimension(:) :: ypmax
- real(kind=dp), allocatable, dimension(:) :: zpmin
- real(kind=dp), allocatable, dimension(:) :: zpmax
- integer :: Npoly
- integer, allocatable, dimension(:) :: iistart
- integer, allocatable, dimension(:) :: iiend
- integer, allocatable, dimension(:) :: ipsection
-
-contains
- !> Increase size of global polyline array.
- !! Specify new size and whether existing points need to be maintained.
- subroutine increasepol(N, jaKeepExisting)
- use m_missing
- use m_alloc
- implicit none
- integer :: n !< Desired new minimum size
- integer :: jaKeepExisting !< Whether or not (1/0) to keep existing points.
- logical :: jakeep
- integer :: maxpolcur
- integer :: ierr
-
- maxpolcur = size(xpl)
- if (N <= maxpolcur) then
- return
- end if
- MAXPOL = max(100000, int(5d0 * N))
-
- jakeep = jaKeepExisting == 1
-
- call realloc(xpl, maxpol, keepExisting=jakeep, fill=dxymis, stat=ierr)
- call realloc(ypl, maxpol, keepExisting=jakeep, fill=dxymis, stat=ierr)
- call realloc(zpl, maxpol, keepExisting=jakeep, fill=dxymis, stat=ierr)
-
- if (jakol45 == 1) then
- call realloc(dzl, maxpol, keepExisting=jakeep, fill=dxymis, stat=ierr)
- call realloc(dzr, maxpol, keepExisting=jakeep, fill=dxymis, stat=ierr)
- else if (jakol45 == 2) then
- call realloc(dcrest, maxpol, keepExisting=jakeep, fill=dxymis, stat=ierr)
- call realloc(dzl, maxpol, keepExisting=jakeep, fill=dxymis, stat=ierr)
- call realloc(dzr, maxpol, keepExisting=jakeep, fill=dxymis, stat=ierr)
- call realloc(dtl, maxpol, keepExisting=jakeep, fill=dxymis, stat=ierr)
- call realloc(dtr, maxpol, keepExisting=jakeep, fill=dxymis, stat=ierr)
- call realloc(dveg, maxpol, keepExisting=jakeep, fill=dxymis, stat=ierr)
- call realloc(iweirt, maxpol, keepExisting=jakeep, stat=ierr)
- end if
-
- ! make sure nampli is allocated
- if (.not. allocated(nampli)) then
- allocate (nampli(0))
- end if
-
- end subroutine increasepol
-
- !> Copies the global polygon into the backup polygon arrays.
- subroutine SAVEPOL()
-
- use m_alloc
- use m_missing
- implicit none
-
- if (NPL > 0) then
- call realloc(xph, maxpol, keepExisting=.false.)
- call realloc(yph, maxpol, keepExisting=.false.)
- call realloc(zph, maxpol, keepExisting=.false.)
- XPH(1:NPL) = XPL(1:NPL)
- YPH(1:NPL) = YPL(1:NPL)
- ZPH(1:NPL) = ZPL(1:NPL)
- end if
-
- MPS = MP
- NPH = NPL
-
- return
- end subroutine savepol
-
- !> Puts back a previously saved backup polygon into the global polygon arrays.
- subroutine RESTOREPOL()
- use m_alloc
- use m_missing
- implicit none
-
- maxpol = max(maxpol, nph)
- call realloc(xpl, maxpol, keepExisting=.false.)
- call realloc(ypl, maxpol, keepExisting=.false.)
- call realloc(zpl, maxpol, keepExisting=.false.)
-
- if (NPH > 0) then
- XPL(1:NPH) = XPH(1:NPH)
- YPL(1:NPH) = YPH(1:NPH)
- ZPL(1:NPH) = ZPH(1:NPH)
- deallocate(XPH, YPH, ZPH)
- end if
- MP = MPS
- NPL = NPH
-
- return
- end subroutine restorepol
-
- function m_polygon_destructor() result(ierr)
-
- implicit none
-
- integer :: ierr
-
- ierr = 0
-
- if (allocated(XPL) .and. ierr == 0) deallocate (XPL, stat=ierr)
- if (allocated(YPL) .and. ierr == 0) deallocate (YPL, stat=ierr)
- if (allocated(ZPL) .and. ierr == 0) deallocate (ZPL, stat=ierr)
- if (allocated(XPH) .and. ierr == 0) deallocate (XPH, stat=ierr)
-
- if (allocated(YPH) .and. ierr == 0) deallocate (YPH, stat=ierr)
- if (allocated(ZPH) .and. ierr == 0) deallocate (ZPH, stat=ierr)
- if (allocated(ZPH) .and. ierr == 0) deallocate (ZPH, stat=ierr)
-
- if (allocated(DZL) .and. ierr == 0) deallocate (DZL, stat=ierr)
- if (allocated(DZR) .and. ierr == 0) deallocate (DZR, stat=ierr)
- if (allocated(DCREST) .and. ierr == 0) deallocate (DCREST, stat=ierr)
- if (allocated(DTL) .and. ierr == 0) deallocate (DTL, stat=ierr)
- if (allocated(DTR) .and. ierr == 0) deallocate (DTR, stat=ierr)
- if (allocated(DVEG) .and. ierr == 0) deallocate (DVEG, stat=ierr)
- if (allocated(IWEIRT) .and. ierr == 0) deallocate (IWEIRT, stat=ierr)
-
- if (allocated(xpmin) .and. ierr == 0) deallocate (xpmin, stat=ierr)
- if (allocated(ypmin) .and. ierr == 0) deallocate (ypmin, stat=ierr)
- if (allocated(xpmax) .and. ierr == 0) deallocate (xpmax, stat=ierr)
- if (allocated(ypmax) .and. ierr == 0) deallocate (ypmax, stat=ierr)
- if (allocated(zpmin) .and. ierr == 0) deallocate (zpmin, stat=ierr)
- if (allocated(zpmax) .and. ierr == 0) deallocate (zpmax, stat=ierr)
- if (allocated(iistart) .and. ierr == 0) deallocate (iistart, stat=ierr)
- if (allocated(iiend) .and. ierr == 0) deallocate (iiend, stat=ierr)
- if (allocated(ipsection) .and. ierr == 0) deallocate (ipsection, stat=ierr)
-
- jakol45 = 0
- dxuni = 40d0
- MAXPOLY = 1000
- NPL = 0
- NPH = 0
- MAXPOL = 0
- MP = 0
- MPS = 0
- Npoly = 0
-
- end function m_polygon_destructor
-
-end module m_polygon
-
!
! Stores the coordinates of the cells
!