subroutine gr8_connect(nxy,x,y,bval,eval)
  use gildas_def
  use greg_interfaces
  !---------------------------------------------------------------------
  ! @ no-interface (because of type mismatch)
  !   Connect a polyline with blanking value
  !---------------------------------------------------------------------
  integer(kind=4) :: nxy                    ! Number of data points
  real(kind=8)    :: x(nxy)                 ! Array of X coordinates
  real(kind=8)    :: y(nxy)                 ! Array of Y coordinates
  real(kind=8)    :: bval                   ! Blanking value
  real(kind=8)    :: eval                   ! Tolerance on blanking value
  ! Local
  integer(kind=size_length) :: j,n,js
  integer(kind=size_length), parameter :: gtv_max_poly=1024  ! GTV internal limit for polylines
  ! Buffers are SAVE'd to avoid reallocation each time entering this subroutine. Is this useful?
  real(kind=4), save :: xwork(gtv_max_poly), ywork(gtv_max_poly)
  !
  if (nxy.lt.2) return
  j = 1
  js= 1
  n = 0
  do while (.true.)
    if (y(j).eq.y(j).and.abs(y(j)-bval).gt.eval) then
      if (n.eq.gtv_max_poly) then
        call us8_to_int(x(js),y(js),xwork,ywork,n)
        call grpoly(n,xwork,ywork)
        js = j-1
        n = 1
      endif
      if (j.eq.nxy) then
        n = n+1
        call us8_to_int(x(js),y(js),xwork,ywork,n)
        if (n.gt.1) then
          call grpoly(n,xwork,ywork)
        else
          call grelocate(xwork(1),ywork(1))
          call gdraw(xwork,ywork)
        endif
        return
      endif
      n = n+1
      j = j+1
    else
      if (n.gt.1) then
        call us8_to_int(x(js),y(js),xwork,ywork,n)
        call grpoly(n,xwork,ywork)
      elseif (n.eq.1) then
        call us8_to_int(x(js),y(js),xwork,ywork,n)
        call grelocate(xwork(1),ywork(1))
        call gdraw(xwork,ywork)
      endif
      n = 0
      j = j+1
      if (j.gt.nxy) return
      do while ( (y(j).ne.y(j)).or.(abs(y(j)-bval).le.eval) )
        j = j+1
        if (j.gt.nxy) return
      enddo
      js = j
    endif
  enddo
end subroutine gr8_connect
!
subroutine gr4_connect(nxy,x,y,bval,eval)
  use gildas_def
  use greg_interfaces
  !---------------------------------------------------------------------
  ! @ no-interface (because of type mismatch)
  !   Connect a polyline with blanking value
  !---------------------------------------------------------------------
  integer(kind=4) :: nxy                    ! Number of data points
  real(kind=4)    :: x(nxy)                 ! Array of X coordinates
  real(kind=4)    :: y(nxy)                 ! Array of Y coordinates
  real(kind=4)    :: bval                   ! Blanking value
  real(kind=4)    :: eval                   ! Tolerance on blanking value
  ! Local
  integer(kind=size_length) :: j,n,js
  integer(kind=size_length), parameter :: gtv_max_poly=1024  ! GTV internal limit for polylines
  ! Buffers are SAVE'd to avoid reallocation each time entering this subroutine. Is this useful?
  real(kind=4), save :: xwork(gtv_max_poly), ywork(gtv_max_poly)
  !
  if (nxy.lt.2) return
  j = 1
  js= 1
  n = 0
  do while (.true.)
    if (y(j).eq.y(j).and.abs(y(j)-bval).gt.eval) then
      if (n.eq.gtv_max_poly) then
        call us4_to_int(x(js),y(js),xwork,ywork,n)
        call grpoly(n,xwork,ywork)
        js = j-1
        n = 1
      endif
      if (j.eq.nxy) then
        n = n+1
        call us4_to_int(x(js),y(js),xwork,ywork,n)
        if (n.gt.1) then
          call grpoly(n,xwork,ywork)
        else
          call grelocate(xwork(1),ywork(1))
          call gdraw(xwork,ywork)
        endif
        return
      endif
      n = n+1
      j = j+1
    else
      if (n.gt.1) then
        call us4_to_int(x(js),y(js),xwork,ywork,n)
        call grpoly(n,xwork,ywork)
      elseif (n.eq.1) then
        call us4_to_int(x(js),y(js),xwork,ywork,n)
        call grelocate(xwork(1),ywork(1))
        call gdraw(xwork,ywork)
      endif
      n = 0
      j = j+1
      if (j.gt.nxy) return
      do while ( (y(j).ne.y(j)).or.(abs(y(j)-bval).le.eval) )
        j = j+1
        if (j.gt.nxy) return
      enddo
      js = j
    endif
  enddo
end subroutine gr4_connect
!
subroutine gr8_marker(nxy,x,y,bval,eval)
  use gildas_def
  use greg_interfaces, except_this=>gr8_marker
  !---------------------------------------------------------------------
  ! @ public-mandatory (because symbol is used elsewhere)
  !   Plot markers with blanking value
  !---------------------------------------------------------------------
  integer(kind=4) :: nxy                    ! Number of data points
  real(kind=8)    :: x(nxy)                 ! Array of X coordinates
  real(kind=8)    :: y(nxy)                 ! Array of Y coordinates
  real(kind=8)    :: bval                   ! Blanking value
  real(kind=8)    :: eval                   ! Tolerance on blanking value
  ! Local
  integer(kind=4) :: nsides,istyle
  integer(kind=size_length) :: in,is,ne,nxysl
  real(kind=4) :: zfact
  real(kind=8) :: z
  !
  if (nxy.lt.1) return
  call inqnsides(nsides)
  call inqsty(istyle)
  call setdas(1)
  !
  nxysl = nxy
  in = 1
  z = 0.d0  ! Ignored with zfact<0
  zfact = -1.0  ! No factor applied on Z values = ignore Z values
  do while (in.ne.0)
    call find_blank8(y,bval,eval,nxysl,is,ne,in)
    call points(nsides,istyle,zfact,1.,x(is),y(is),z,ne,.true.)
  enddo
end subroutine gr8_marker
!
subroutine gr4_marker(nxy,x,y,bval,eval)
  use greg_interfaces, except_this=>gr4_marker
  !---------------------------------------------------------------------
  ! @ public-mandatory (because symbol is used elsewhere)
  !   Plot markers with blanking value
  !---------------------------------------------------------------------
  integer(kind=4) :: nxy                    ! Number of data points
  real(kind=4)    :: x(nxy)                 ! Array of X coordinates
  real(kind=4)    :: y(nxy)                 ! Array of Y coordinates
  real(kind=4)    :: bval                   ! Blanking value
  real(kind=4)    :: eval                   ! Tolerance on blanking value
  ! Local
  integer(kind=4) :: j,nsides,istyle
  !
  if (nxy.lt.1) return
  call inqnsides(nsides)
  call inqsty(istyle)
  call setdas(1)
  !
  do j = 1,nxy
    if (y(j).eq.y(j).and.abs(y(j)-bval).gt.eval) then
      call relocate(dble(x(j)),dble(y(j)))
      call gr_point(nsides,istyle)
    endif
  enddo
end subroutine gr4_marker
!
subroutine points(nsides,istyle,zfact,expo,x,y,z,nxy,same_marker)
  use gildas_def
  use greg_dependencies_interfaces
  use greg_interfaces
  !---------------------------------------------------------------------
  ! @ no-interface (because of argument type mismatch)
  ! GREG Internal routine
  !  Plot symbols at each point (X,Y) in user coordinates
  !  If ZFACT .GT. 0. symbol size is proportional to Z value with power
  ! law of exponent EXPO
  !---------------------------------------------------------------------
  integer(kind=size_length) :: nxy          !
  integer(kind=4)           :: nsides(nxy)  !
  integer(kind=4)           :: istyle(nxy)  !
  real(kind=4)              :: zfact        !
  real(kind=4)              :: expo         !
  real(kind=8)              :: x(nxy)       !
  real(kind=8)              :: y(nxy)       !
  real(kind=8)              :: z(nxy)       !
  logical                   :: same_marker  !
  ! Local
  real(kind=4) :: size,symsiz
  integer(kind=size_length) :: j
  integer(kind=4) :: np,ier
  real(kind=4), allocatable :: xp(:),yp(:)
  logical :: error
  !
  if (nxy.lt.1) return
  call setdas(1)
  !
  if (same_marker .and. nsides(1).lt.2) then
    ! A list of dot-points. Use optimized API
    allocate(xp(nxy),yp(nxy),stat=ier)
    error = .false.
    if (failed_allocate('POINTS','XP and XP',ier,error))  return
    !
    np = nxy
    call gr8_user_phys (x,y,xp,yp,np)  ! Convert from user to plot coordinates
    call grdots(nxy,xp,yp)
    deallocate(xp,yp)
    !
  elseif (zfact.le.0.e0) then
    ! A list of points (any kind), default size
    if (same_marker) then      ! Same marker type for all points
      do j = 1,nxy
        call relocate(x(j),y(j))
        call gr_point(nsides(1),istyle(1))
      enddo
    else                       !
      do j = 1,nxy
        call relocate(x(j),y(j))
        call gr_point(nsides(j),istyle(j))
      enddo
    endif
    !
  else
    ! A list of points (any kind), custom size
    call inqsym(symsiz)
    if (same_marker) then      ! Same marker type for all points
      do j = 1,nxy
        size = zfact*abs(z(j))**expo
        call setsym (size)
        call relocate(x(j),y(j))
        call gr_point(nsides(1),istyle(1))
      enddo
    else
      do j = 1,nxy
        size = zfact*abs(z(j))**expo
        call setsym (size)
        call relocate(x(j),y(j))
        call gr_point(nsides(j),istyle(j))
      enddo
    endif
    call setsym(symsiz)
  endif
  !
end subroutine points
!
subroutine gr8_text(nxy,x,y,text,code,bval,eval)
  use greg_dependencies_interfaces
  use greg_interfaces, except_this=>gr8_text
  use greg_kernel
  !---------------------------------------------------------------------
  ! @ public
  !   Plot text with blanking value
  ! CODE (1-9) of text placement (ex: 5=center); negative values for
  ! "append" code
  !---------------------------------------------------------------------
  integer(kind=4)  :: nxy           ! Number of data points
  real(kind=8)     :: x(nxy)        ! Array of X coordinates
  real(kind=8)     :: y(nxy)        ! Array of Y coordinates
  character(len=*) :: text          ! TEXT to be plotted
  integer(kind=4)  :: code          ! CODE (1-9) of text placement
  real(kind=8)     :: bval          ! Blanking value
  real(kind=8)     :: eval          ! Tolerance on blanking value
  ! Local
  integer(kind=4) :: nchar,ii,j
  logical :: user
  !
  if (nxy.lt.1) return
  user = (code.ge.0)
  if (user) then
    ii = code
    if (code.eq.0) ii = centre(xcurse,ycurse)
  else
    ii = -code
  endif
  nchar=lenc(text)
  !
  do j = 1,nxy
    if (y(j).eq.y(j).and.abs(y(j)-bval).gt.eval) then
      if (user) call relocate(x(j),y(j))
      call putlabel(nchar,text,ii,tangle,.false.)
    endif
  enddo
end subroutine gr8_text
!
subroutine gr4_text(nxy,x,y,text,code,bval,eval)
  use greg_dependencies_interfaces
  use greg_interfaces, except_this=>gr4_text
  use greg_kernel
  !---------------------------------------------------------------------
  ! @ public
  !   Plot text with blanking value
  ! CODE (1-9) of text placement (ex: 5=center); negative values for
  ! "append" code
  !---------------------------------------------------------------------
  integer(kind=4)  :: nxy           ! Number of data points
  real(kind=4)     :: x(nxy)        ! Array of X coordinates
  real(kind=4)     :: y(nxy)        ! Array of Y coordinates
  character(len=*) :: text          ! TEXT to be plotted
  integer(kind=4)  :: code          ! CODE (1-9) of text placement
  real(kind=4)     :: bval          ! Blanking value
  real(kind=4)     :: eval          ! Tolerance on blanking value
  ! Local
  integer(kind=4) :: nchar,ii,j
  logical :: user
  !
  if (nxy.lt.1) return
  user = (code.ge.0)
  if (user) then
    ii = code
    if (code.eq.0) ii = centre(xcurse,ycurse)
  else
    ii = -code
  endif
  nchar=lenc(text)
  !
  do j = 1,nxy
    if (y(j).eq.y(j).and.abs(y(j)-bval).gt.eval) then
      if (user) call relocate(dble(x(j)),dble(y(j)))
      call putlabel(nchar,text,ii,tangle,.false.)
    endif
  enddo
end subroutine gr4_text
!
subroutine gr8_hatch(rname,nxy,x,y,angle,separ,phase,error)
  use gildas_def
  use gbl_message
  use greg_dependencies_interfaces
  use greg_interfaces, except_this=>gr8_hatch
  !---------------------------------------------------------------------
  ! @ public
  ! Hatch the input polygon with parallel lines. Polygon must be closed
  ! (last point = first point)
  !---------------------------------------------------------------------
  character(len=*),          intent(in)    :: rname   ! Calling routine name
  integer(kind=size_length), intent(in)    :: nxy     ! Number of points
  real(kind=8),              intent(in)    :: x(nxy)  ! X coordinates (user units)
  real(kind=8),              intent(in)    :: y(nxy)  ! Y coordinates (user units)
  real(kind=4),              intent(in)    :: angle   ! Hatching angle (radians)
  real(kind=4),              intent(in)    :: separ   ! Hatching separation (physical units)
  real(kind=4),              intent(in)    :: phase   ! Hatching phase (0. to 1.)
  logical,                   intent(inout) :: error   ! Logical error flag
  ! Local
  real(kind=4) :: x2(nxy),y2(nxy),x3(nxy),y3(nxy)  ! Automatic arrays
  real(kind=4) :: y3min,y3max,xl4(1024),xu4(1024),y4,cosa,sina,x5,y5
  integer(kind=size_length) :: j
  integer(kind=4) :: nr(2),lnx,inx
  !
  ! Sanity checks
  if (separ.eq.0.) then
    call greg_message(seve%e,rname,'Hatching separation must be non-zero')
    error = .true.
    return
  endif
  !
  ! 1) Convert to physical units
  call gr8_user_phys(x,y,x2,y2,int(nxy,kind=4))
  !
  ! 2) Rotate the coordinates (BLTLIS can draw only horizontal lines)
  cosa = cos(-angle)
  sina = sin(-angle)
  do j=1,nxy
    x3(j) = x2(j)*cosa-y2(j)*sina
    y3(j) = x2(j)*sina+y2(j)*cosa
  enddo
  y3min = minval(y3)
  y3max = maxval(y3)
  !
  ! 3) Compute segments striking though the polygon + derotate
  nr(1) = nxy
  ! The floor() below ensures that all the lines are aligned for all
  ! polygons on the plot. The phase allow to shift them on purpose.
  y4 = (floor(y3min/abs(separ))+phase)*abs(separ)
  do while (y4.lt.y3max)
    call gr4_bltlis(1,1,1,nr,x3,y3,y4,lnx,xl4,xu4)
    do inx=1,lnx
      ! Left
      x5 =  xl4(inx)*cosa+y4*sina
      y5 = -xl4(inx)*sina+y4*cosa
      call grelocate(x5,y5)
      ! Right
      x5 =  xu4(inx)*cosa+y4*sina
      y5 = -xu4(inx)*sina+y4*cosa
      call gdraw(x5,y5)
    enddo
    y4 = y4+abs(separ)
  enddo
  !
end subroutine gr8_hatch
