make_composite_mask Subroutine

private subroutine make_composite_mask(msk, n_cells, locus, a, b, width, height, shap, long, larg)

Note

The subroutine generates a composite mask based on specified parameters. The mask is filled with a number of shapes (in this case, ellipses) placed randomly within a defined area, while ensuring that the shapes do not overlap.

  • If the locus is set to ‘center’, the subroutine immediately centers a single shape in the mask.
  • If not centered, it attempts to randomly place the specified number of shapes (n_cells) within the mask. The algorithm limits attempts to place shapes to avoid overlaps.
  • The routine uses random numbers to determine the position of each shape, ensuring that they fit within the given dimensions and do not exceed the boundaries of the mask.
  • A separate temporary mask (msk_quad) is used to track where shapes have already been placed, preventing overlaps.
  • The process continues until the desired number of shapes is successfully placed or until a maximum number of attempts is reached (to avoid infinite loops).

Arguments

Type IntentOptional Attributes Name
integer(kind=I4), intent(out), dimension(1:long, 1:larg) :: msk

Output mask that will be filled with shapes

integer(kind=I4), intent(in) :: n_cells

Number of cells to create in the composite mask

character(len=6), intent(in) :: locus

Position of the shape (e.g., ‘center’ for centering)

integer(kind=I4), intent(in) :: a

ellipsis first parameter

integer(kind=I4), intent(in) :: b

ellipsis second parameter

integer(kind=I4), intent(in) :: width

Width of each shape to be drawn in the mask

integer(kind=I4), intent(in) :: height

Height of each shape to be drawn in the mask

character(len=8), intent(in) :: shap

Type of shape to be drawn (here, ‘ellipsis’ is used)

integer(kind=I4), intent(in) :: long

Length (dimensions) of the mask

integer(kind=I4), intent(in) :: larg

Width (dimensions) of the mask


Calls

proc~~make_composite_mask~~CallsGraph proc~make_composite_mask make_composite_mask proc~make_mask make_mask proc~make_composite_mask->proc~make_mask

Source Code

   subroutine make_composite_mask(msk, n_cells, locus, a, b, width, height, shap, long, larg)
   !================================================================================================
   !< @note
   !<
   !< The subroutine generates a composite mask based on specified parameters.
   !< The mask is filled with a number of shapes (in this case, ellipses) placed randomly within a defined area, while ensuring that the shapes do not overlap.
   !<
   !< + If the `locus` is set to 'center', the subroutine immediately centers a single shape in the mask.
   !< + If not centered, it attempts to randomly place the specified number of shapes (`n_cells`) within the mask.
   !<   The algorithm limits attempts to place shapes to avoid overlaps.
   !< + The routine uses random numbers to determine the position of each shape, ensuring that they fit within the given dimensions and do not exceed the boundaries of the mask.
   !< + A separate temporary mask (`msk_quad`) is used to track where shapes have already been placed, preventing overlaps.
   !< + The process continues until the desired number of shapes is successfully placed or until a maximum number of attempts is reached (to avoid infinite loops).
   !<
   !< @endnote
   !------------------------------------------------------------------------------------------------
   implicit none
   integer  (kind=I4), intent(in)                              :: n_cells   !! *Number of cells to create in the composite mask*
   integer  (kind=I4), intent(in)                              :: long      !! *Length (dimensions) of the mask*
   integer  (kind=I4), intent(in)                              :: larg      !! *Width (dimensions) of the mask*
   integer  (kind=I4), intent(in)                              :: width     !! *Width of each shape to be drawn in the mask*
   integer  (kind=I4), intent(in)                              :: height    !! *Height of each shape to be drawn in the mask*
   integer  (kind=I4), intent(in)                              :: a         !! *ellipsis first parameter*
   integer  (kind=I4), intent(in)                              :: b         !! *ellipsis second parameter*
   character(len = 8), intent(in)                              :: shap      !! *Type of shape to be drawn (here, 'ellipsis' is used)*
   character(len = 6), intent(in)                              :: locus     !! *Position of the shape (e.g., 'center' for centering)*
   integer  (kind=I4), intent(out), dimension(1:long, 1:larg)  :: msk       !! *Output mask that will be filled with shapes*

      ! Declaration of local variables
      integer(kind=I4) :: icells, x0, y0, iter, itry
      real   (kind=R8) :: x, y

      ! Temporary masks to manage the shapes
      integer(kind=I4), dimension(1:long, 1:larg) :: msk_quad, msk_shap

      ! Initialize the output mask to zero
      msk(1:long, 1:larg) = 0

      ! If the position is centered, calculate the central coordinates
      if (locus == 'center') then

         x0 = long / 2 + 1       ! x-coordinate of the center
         y0 = larg / 2 + 1       ! y-coordinate of the center

         ! Call the subroutine to create a centered ellipse mask
         call make_mask(x0 = x0,          &  !
                        y0 = y0,          &  !
                         a = a,           &  !
                         b = b,           &  !
                      shap = 'ellipsis',  &  !
                       msk = msk,         &  !
                      long = long,        &  !
                      larg = larg)           !
         return

      endif

      ! Initialize the attempt counter for placing cells
      itry = 0
l1:   do

      itry = itry + 1               ! Increment the attempt counter
      if (itry > 100) exit l1       ! Limit the number of tries to 100

      msk_quad(1:long, 1:larg) = 0  ! Reset the quadrilateral mask
      msk(1:long, 1:larg) = 0       ! Reset the final mask

      icells = 0                    ! Cell placement counter
      iter = 0                      ! Iteration counter for placement

l2:   do

         iter = iter + 1            ! Increment the iteration counter
         if (iter > 200) cycle l1   ! Limit the number of iterations to 200

         ! Display the current state of the iteration and the number of cells
         write(*,*) iter, icells

         call random_number(x)                           ! Generate a random number for x
         x0 = width / 2 + 1 + x * (long - width - 1)     ! Calculate the x-coordinate of the center of the shape
         call random_number(y)                           ! Generate a random number for y
         y0 = height / 2 + 1 + y * (larg - height - 1)   ! Calculate the y-coordinate of the center of the shape

         msk_shap(1:long, 1:larg) = 0                    ! Reset the temporary shape mask

         ! Define the shape mask over a square area centered on (x0, y0)
         msk_shap(x0 - width  / 2:x0 + width / 2,        &  !
                  y0 - height / 2:y0 + height / 2) = 1      !

         ! Check if the shape does not overlap with an already placed shape
         if (sum(msk_quad(1:long, 1:larg) * msk_shap(1:long, 1:larg)) > 0) cycle l2

         ! Call the subroutine to create an ellipse mask at coordinates (x0, y0)
         call make_mask(x0 = x0,             &  !
                        y0 = y0,             &  !
                         a = a,              &  !
                         b = b,              &  !
                      shap = 'ellipsis',     &  !
                       msk = msk,            &  !
                      long = long,           &  !
                      larg = larg)              !

         msk_quad(x0 - width  / 2:x0 + width / 2,        &  !
                  y0 - height / 2:y0 + height / 2) = 1      ! Mark the area of the placed shape

         icells = icells + 1                                ! Increment the count of placed cells

         if (icells == n_cells) exit l1                     ! Exit if the desired number of cells has been reached

      enddo l2

      enddo l1

   return
   endsubroutine make_composite_mask