! ------------------------------------------------------------------------------
!
!  Gmsh Fortran tutorial 15
!
!  Embedded points, lines and surfaces
!
! ------------------------------------------------------------------------------

! By default, across geometrical dimensions meshes generated by Gmsh are only
! conformal if lower dimensional entities are on the boundary of higher
! dimensional ones (i.e. if points, curves or surfaces are part of the boundary
! of volumes).

! Embedding constraints allow to force a mesh to be conformal to other lower
! dimensional entities.

program t15

use, intrinsic :: iso_c_binding
use gmsh

implicit none
type(gmsh_t) :: gmsh
integer(c_int) :: ret, p
integer(c_int), allocatable :: tags(:,:)
real(c_double) :: lc, l
character(len=GMSH_API_MAX_STR_LEN) :: cmd

call gmsh%initialize()

! Copied from `t1.f90'...
lc = 1e-2
ret = gmsh%model%geo%addPoint(.0d0, .0d0, 0d0, lc, 1)
ret = gmsh%model%geo%addPoint(.1d0, .0d0, 0d0, lc, 2)
ret = gmsh%model%geo%addPoint(.1d0, .3d0, 0d0, lc, 3)
ret = gmsh%model%geo%addPoint(.0d0, .3d0, 0d0, lc, 4)
ret = gmsh%model%geo%addLine(1, 2, 1)
ret = gmsh%model%geo%addLine(3, 2, 2)
ret = gmsh%model%geo%addLine(3, 4, 3)
ret = gmsh%model%geo%addLine(4, 1, 4)
ret = gmsh%model%geo%addCurveLoop([4, 1, -2, 3], 1)
ret = gmsh%model%geo%addPlaneSurface([1], 1)

! We change the mesh size to generate a coarser mesh
lc = lc * 4
call gmsh%model%geo%mesh%setSize(reshape([0, 1, 0, 2, 0, 3, 0, 4], [2, 4]), lc)

! We define a new point
ret = gmsh%model%geo%addPoint(0.02d0, 0.02d0, 0.d0, lc, 5)

! We have to synchronize before embedding entites:
call gmsh%model%geo%synchronize()

! One can force this point to be included ("embedded") in the 2D mesh, using the
! `embed()' function:
call gmsh%model%mesh%embed(0, [5], 2, 1)

! In the same way, one can use `embed()' to force a curve to be embedded in the
! 2D mesh:
ret = gmsh%model%geo%addPoint(0.02d0, 0.12d0, 0.d0, lc, 6)
ret = gmsh%model%geo%addPoint(0.04d0, 0.18d0, 0.d0, lc, 7)
ret = gmsh%model%geo%addLine(6, 7, 5)

call gmsh%model%geo%synchronize()
call gmsh%model%mesh%embed(1, [5], 2, 1)

! Points and curves can also be embedded in volumes
call gmsh%model%geo%extrude(reshape([2, 1], [2, 1]), 0d0, 0d0, 0.1d0, tags)

p = gmsh%model%geo%addPoint(0.07d0, 0.15d0, 0.025d0, lc)

call gmsh%model%geo%synchronize()
call gmsh%model%mesh%embed(0, [p], 3, 1)

ret = gmsh%model%geo%addPoint(0.025d0, 0.15d0, 0.025d0, lc, p + 1)
l = gmsh%model%geo%addLine(7, p + 1)

call gmsh%model%geo%synchronize()
call gmsh%model%mesh%embed(1, [int(l)], 3, 1)

! Finally, we can also embed a surface in a volume:
ret = gmsh%model%geo%addPoint(0.02d0, 0.12d0, 0.05d0, lc, p + 2)
ret = gmsh%model%geo%addPoint(0.04d0, 0.12d0, 0.05d0, lc, p + 3)
ret = gmsh%model%geo%addPoint(0.04d0, 0.18d0, 0.05d0, lc, p + 4)
ret = gmsh%model%geo%addPoint(0.02d0, 0.18d0, 0.05d0, lc, p + 5)

ret = gmsh%model%geo%addLine(p + 2, p + 3, int(l + 1))
ret = gmsh%model%geo%addLine(p + 3, p + 4, int(l + 2))
ret = gmsh%model%geo%addLine(p + 4, p + 5, int(l + 3))
ret = gmsh%model%geo%addLine(p + 5, p + 2, int(l + 4))

ret = gmsh%model%geo%addCurveLoop([int(l) + 1, int(l) + 2, int(l) + 3, int(l) + 4])
ret = gmsh%model%geo%addPlaneSurface([ret])

call gmsh%model%geo%synchronize()
call gmsh%model%mesh%embed(2, [ret], 3, 1)

! Note that with the OpenCASCADE kernel (see `t16.f90'), when the `fragment()'
! function is applied to entities of different dimensions, the lower dimensional
! entities will be autmatically embedded in the higher dimensional entities if
! necessary.

call gmsh%model%mesh%generate(3)

call gmsh%write("t15.msh")

! Launch the GUI to see the results:
call get_command(cmd)
if (index(cmd, "-nopopup") == 0) call gmsh%fltk%run()

call gmsh%finalize()

end program t15
