subroutine gtv_fillpoly(n,x,y,vert,error)
  use gtv_interfaces, except_this=>gtv_fillpoly
  use gtv_tree
  use gtv_buffers
  use gtv_graphic
  use gtv_plot
  use gbl_message
  !---------------------------------------------------------------------
  ! @ public
  !     Plot a filled polygon. Filling based on Horizontal scanning.
  !     or Vertical scanning if VERT = .TRUE.
  ! ---
  !   Threads status: thread safe
  !---------------------------------------------------------------------
  integer(kind=4), intent(in)    :: n      ! Number of points
  real(kind=4),    intent(in)    :: x(n)   !
  real(kind=4),    intent(in)    :: y(n)   !
  logical,         intent(in)    :: vert   ! Horizontal or vertical polygon?
  logical,         intent(inout) :: error  ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='GTV_FILLPOLY'
  integer :: seg_kind,ier
  !
  if (.not.awake .or. error_condition) return
  if (n.le.0)  return  ! No data
  !
  if (.not.associated(co_segment)) then
    call gtv_message(seve%e,rname,'Programming error: no segment opened')
    error = .true.
    return
  endif
  !
  ! First flush POLYL%X and POLYL%Y buffers if they are not empty
  call gtx_frxry(error)
  if (error) return
  !
  ! Do we need to save the current PENLUT in the metacode before starting
  ! to write the polygon?
  if (lut_static) then
    if (.not.associated(co_segment%head%lut)) then
      ! We have to save the current global PENLUT in the metacode
      call gt_penlut_segdata(error)  ! This sets co_segment%head%lut
      if (error)  return
    endif
  endif
  !
  ! Update minmax
  co_segment%head%gen%minmax(1) = min(minval(x),co_segment%head%gen%minmax(1))  ! xmin
  co_segment%head%gen%minmax(2) = max(maxval(x),co_segment%head%gen%minmax(2))  ! xmax
  co_segment%head%gen%minmax(3) = min(minval(y),co_segment%head%gen%minmax(3))  ! ymin
  co_segment%head%gen%minmax(4) = max(maxval(y),co_segment%head%gen%minmax(4))  ! ymax
  !
  if (vert) then
    seg_kind = seg_vfpoly
  else
    seg_kind = seg_hfpoly
  endif
  !
  call gtv_open_segments_for_writing_from_main()
  !
  if (.not.associated(co_segment_data)) then
    allocate(co_segment%data,stat=ier)
    if (ier.ne.0) then
      call gtv_message(seve%e,rname,'Internal error: allocation failure (1)')
      error = .true.
      goto 10
    endif
    co_segment_data => co_segment%data
  else
    allocate(co_segment_data%nextdata,stat=ier)
    if (ier.ne.0) then
      call gtv_message(seve%e,rname,'Internal error: allocation failure (2)')
      error = .true.
      goto 10
    endif
    co_segment_data => co_segment_data%nextdata
  endif
  co_segment_data%nextdata => null()
  !
  ! Store the data
  allocate(co_segment_data%poly%x(n),co_segment_data%poly%y(n),stat=ier)
  if (ier.ne.0) then
    call gtv_message(seve%e,rname,'Internal error: allocation failure (3)')
    error = .true.
    goto 10
  endif
  co_segment_data%kind = seg_kind
  co_segment_data%poly%n = n
  co_segment_data%poly%x = x
  co_segment_data%poly%y = y
  co_segment_data%poly%penlut => co_segment%head%lut  ! Which can be null()
  !
10 continue
  !
  call gtv_close_segments_for_writing_from_main()
  !
end subroutine gtv_fillpoly
!
subroutine gti_fillpoly(out,poly,vert)
  use gtv_types
  use gtv_tree
  use gtv_buffers
  use gtv_graphic
  use gtv_interfaces, except_this=>gti_fillpoly
  use gtv_protocol
  !---------------------------------------------------------------------
  ! @ private
  !   Draws a filled polygon. Filling based on Horizontal scanning.
  !---------------------------------------------------------------------
  type(gt_display),  intent(inout) :: out   ! Input gt_display
  type(gt_polyline), intent(in)    :: poly  !
  logical,           intent(in)    :: vert  !
  ! Local
  integer(kind=4) :: i
  integer(kind=4), allocatable :: x_poly(:),y_poly(:)
  !
  if (.not.awake .or. error_condition) return
  ! call gtx_pen(out,ipenx_i)
  !
  ! No device selected
  if (out%dev%protocol.eq.p_null)  return
  !
  if (associated(poly%penlut)) then
    ! LUT STATIC:
    ! Load the appropriate pen into the device
    call gtx_pen(out,out%icolou,poly%penlut)
  endif
  !
  ! Tracons...
  select case (out%dev%protocol)
  case(p_x)
    allocate(x_poly(poly%n),y_poly(poly%n))
    do i = 1,poly%n
      call world_to_pixel(out,poly%x(i),poly%y(i),x_poly(i),y_poly(i))
    enddo
    call x_fill_poly(out%x%graph_env,poly%n,x_poly,y_poly)
    deallocate(x_poly,y_poly)
    !
  case(p_postscript)
    call ps_fill(poly%n,poly%x,poly%y)
    !
  case(p_svg)
    call svg_fill(out,poly%n,poly%x,poly%y)
    !
  case(p_png)
    call png_fill(out,poly%n,poly%x,poly%y)
    !
  end select
  !
end subroutine gti_fillpoly
!
subroutine gi4_bltlis(lpoly,llv,npoly,nvert,xv,yv,iy,lnx,ixl,ixu)
  use gtv_interfaces, except_this=>gi4_bltlis
  !---------------------------------------------------------------------
  ! @ private
  ! From a list of polygons, BLTLIS makes a list of horizontal line
  ! segments included in the polygons. There might several segments
  ! to fill for a row crossed by a single polygon.
  !---------------------------------------------------------------------
  integer(kind=4), intent(in)  :: lpoly      ! Beginning polygon number
  integer(kind=4), intent(in)  :: llv        ! Beginning vertex number
  integer(kind=4), intent(in)  :: npoly      ! Number of polygons
  integer(kind=4), intent(in)  :: nvert(2)   ! Number of vertices in each polygon
  integer(kind=4), intent(in)  :: xv(1024)   ! X position of vertices
  integer(kind=4), intent(in)  :: yv(1024)   ! Y position of vertices
  integer(kind=4), intent(in)  :: iy         ! Row number
  integer(kind=4), intent(out) :: lnx        ! Number of segments
  integer(kind=4), intent(out) :: ixl(1024)  ! Low x index of segments
  integer(kind=4), intent(out) :: ixu(1024)  ! High x index of segments
  ! Local
  integer(kind=4) :: lp,ip,lv,nxe,y1,y2,i,j,ix,k
  logical :: sorted
  integer(kind=4), parameter :: xsegmax=1024  ! Should be greater or equal to ixl/ixu dimension
  real(kind=4) :: rx,ry,ang,angsum,xse(xsegmax)
  !
  lnx = 0
  lp = llv
  ry = iy
  do ip=lpoly,npoly
    lv = nvert(ip) + lp - 2
    ! find intersections
    nxe = 0
    do i=lp,lv
      y1 = yv(i)
      y2 = yv(i+1)
      if (y1.eq.y2) cycle  ! I
      if (iy.lt.y1 .and. iy.lt.y2) cycle  ! I
      if (iy.gt.y1 .and. iy.gt.y2) cycle  ! I
      if (nxe.eq.xsegmax)  cycle  ! Buffers will be exhausted. Silently skip
      nxe = nxe + 1
      xse(nxe) = float(xv(i+1)-xv(i)) * float(iy-y1) / float (y2-y1) + xv(i)
    enddo  ! I
    if (nxe.le.1) go to 70
    !
    ! Sort list (Catastrophically programmed)
    sorted = .false.
    do while (.not.sorted)
      sorted = .true.
      do i = 2,nxe
        if (xse(i-1).gt.xse(i)) then
          rx = xse(i-1)
          xse(i-1) = xse(i)
          xse(i) = rx
          sorted = .false.
        endif
      enddo
    enddo
    !
    ! which are interior
    do i=2,nxe
      rx = (xse(i-1) + xse(i)) / 2.0
      ix = nint (rx)
      ! test for on an edge
      do j=lp,lv
        if (iy.ne.yv(j)) go to 35
        if (ix.eq.xv(j)) go to 55
        if (ix.ge.xv(j) .and. ix.le.xv(j+1) .and. iy.eq.yv(j+1))  go to 55
        if (ix.le.xv(j) .and. ix.ge.xv(j+1) .and. iy.eq.yv(j+1))  go to 55
35      if (ix.ne.xv(j))  cycle
        if (iy.ge.yv(j) .and. iy.le.yv(j+1) .and. ix.eq.xv(j+1))  go to 55
        if (iy.le.yv(j) .and. iy.ge.yv(j+1) .and. ix.eq.xv(j+1))  go to 55
      enddo
      !
      angsum = 0.0
      do j = lp,lv
        call gi4_bltgle (rx, ry, xv(j), yv(j), xv(j+1), yv(j+1), ang)
        angsum = angsum + ang
      enddo
      if (abs(angsum).lt.180.) cycle   ! I
55    lnx = lnx + 1
      ixl(lnx) = nint (xse(i-1))
      ixu(lnx) = nint (xse(i))
    enddo                      ! I
70  lp = lv + 2
  enddo                        ! IP
  !
  if (lnx.le.0) go to 999
  !
  ! compress list
  i = 1
85 if (i.ge.lnx) go to 999
  i = i + 1
90 if (ixu(i-1).ne.ixl(i)) go to 85
  j = lnx - i
  ixu(i-1) = ixu(i)
  lnx = lnx - 1
  if (j.le.0) go to 999
  do k=i+1,i+j
    ixl(k-1) = ixl(k)
  enddo
  do k=i+1,i+j
    ixu(k-1) = ixu(k)
  enddo
  go to 90
  !
999 return
end subroutine gi4_bltlis
!
subroutine gi4_bltgle (xt, yt, x1, y1, x2, y2, ang)
  use gtv_interfaces, except_this=>gi4_bltgle
  !---------------------------------------------------------------------
  ! @ private
  !  Support routine for BLTLIS (INTEGER*4 version)
  !  Returns angle from A through a test position to B
  !  BLTGLE returns the angle in degrees from (X1, Y1) to (XT, YT) to
  ! (X2, Y2).
  !---------------------------------------------------------------------
  real(kind=4),    intent(in)  :: xt   ! Test position (X)
  real(kind=4),    intent(in)  :: yt   ! Test position (Y)
  integer(kind=4), intent(in)  :: x1   ! Mark position 1 (X)
  integer(kind=4), intent(in)  :: y1   ! Mark position 1 (Y)
  integer(kind=4), intent(in)  :: x2   ! Mark position 2 (X)
  integer(kind=4), intent(in)  :: y2   ! Mark position 2 (Y)
  real(kind=4),    intent(out) :: ang  ! Angle between 1 -> T -> 2
  ! Local
  real(kind=4) :: xx1, xx2, yy1, yy2, cross, dot
  real(kind=4), parameter :: r2d=57.29578e0
  !
  ! Vector coordinates
  xx1 = x1 - xt
  yy1 = y1 - yt
  xx2 = x2 - xt
  yy2 = y2 - yt
  ! CROSS prop SIN
  ! DOT prop COS
  cross = xx1 * yy2  -  xx2 * yy1
  dot   = xx1 * xx2  +  yy1 * yy2
  ang = 0.0
  if (cross.ne.0. .or. dot.ne.0.) ang = r2d * atan2 (cross, dot)
end subroutine gi4_bltgle
!
subroutine gr8_bltlis(lpoly,llv,npoly,nvert,xv,yv,iy,lnx,ixl,ixu)
  use gtv_interfaces, except_this=>gr8_bltlis
  !---------------------------------------------------------------------
  ! @ public
  ! From a list of polygons, BLTLIS makes a list of horizontal line
  ! segments included in the polygons. There might several segments
  ! to fill for a row crossed by a single polygon.
  !---------------------------------------------------------------------
  integer(kind=4), intent(in)  :: lpoly      ! Beginning polygon number
  integer(kind=4), intent(in)  :: llv        ! Beginning vertex number
  integer(kind=4), intent(in)  :: npoly      ! Number of polygons
  integer(kind=4), intent(in)  :: nvert(2)   ! Number of vertices in each polygon
  real(kind=8),    intent(in)  :: xv(1024)   ! X position of vertices
  real(kind=8),    intent(in)  :: yv(1024)   ! Y position of vertices
  real(kind=8),    intent(in)  :: iy         ! Row number
  integer(kind=4), intent(out) :: lnx        ! Number of segments
  real(kind=8),    intent(out) :: ixl(1024)  ! Low x index of segments
  real(kind=8),    intent(out) :: ixu(1024)  ! High x index of segments
  ! Local
  integer(kind=4) :: lp,ip,lv,nxe,i,j,k
  real(kind=8) :: y1,y2,ix
  logical :: sorted
  integer(kind=4), parameter :: xsegmax=1024  ! Should be greater or equal to ixl/ixu dimension
  real(kind=4) :: rx,ry,ang,angsum,xse(xsegmax)
  !
  lnx = 0
  lp = llv
  ry = iy
  do ip=lpoly,npoly
    lv = nvert(ip) + lp - 2
    ! find intersections
    nxe = 0
    do i=lp,lv
      y1 = yv(i)
      y2 = yv(i+1)
      if (y1.eq.y2) cycle  ! I
      if (iy.lt.y1 .and. iy.lt.y2) cycle  ! I
      if (iy.gt.y1 .and. iy.gt.y2) cycle  ! I
      if (nxe.eq.xsegmax)  cycle  ! Buffers will be exhausted. Silently skip
      nxe = nxe + 1
      xse(nxe) = (xv(i+1)-xv(i)) * (iy-y1) / (y2-y1) + xv(i)
    enddo  ! I
    if (nxe.le.1) go to 70
    !
    ! Sort list (Catastrophically programmed)
    sorted = .false.
    do while (.not.sorted)
      sorted = .true.
      do i = 2,nxe
        if (xse(i-1).gt.xse(i)) then
          rx = xse(i-1)
          xse(i-1) = xse(i)
          xse(i) = rx
          sorted = .false.
        endif
      enddo
    enddo
    !
    ! which are interior
    do i=2,nxe
      rx = (xse(i-1) + xse(i)) / 2.0
      ix = rx
      ! test for on an edge
      do j=lp,lv
        if (iy.ne.yv(j)) go to 35
        if (ix.eq.xv(j)) go to 55
        if (ix.ge.xv(j) .and. ix.le.xv(j+1) .and. iy.eq.yv(j+1))  go to 55
        if (ix.le.xv(j) .and. ix.ge.xv(j+1) .and. iy.eq.yv(j+1))  go to 55
35      if (ix.ne.xv(j))  cycle
        if (iy.ge.yv(j) .and. iy.le.yv(j+1) .and. ix.eq.xv(j+1))  go to 55
        if (iy.le.yv(j) .and. iy.ge.yv(j+1) .and. ix.eq.xv(j+1))  go to 55
      enddo
      !
      angsum = 0.0
      do j = lp,lv
        call gr8_bltgle (rx, ry, xv(j), yv(j), xv(j+1), yv(j+1), ang)
        angsum = angsum + ang
      enddo
      if (abs(angsum).lt.180.) cycle   ! I
55    lnx = lnx + 1
      ixl(lnx) = xse(i-1)
      ixu(lnx) = xse(i)
    enddo                      ! I
70  lp = lv + 2
  enddo                        ! IP
  !
  if (lnx.le.0) go to 999
  !
  ! compress list
  i = 1
85 if (i.ge.lnx) go to 999
  i = i + 1
90 if (ixu(i-1).ne.ixl(i)) go to 85
  j = lnx - i
  ixu(i-1) = ixu(i)
  lnx = lnx - 1
  if (j.le.0) go to 999
  do k=i+1,i+j
    ixl(k-1) = ixl(k)
  enddo
  do k=i+1,i+j
    ixu(k-1) = ixu(k)
  enddo
  go to 90
  !
999 return
end subroutine gr8_bltlis
!
subroutine gr8_bltgle (xt, yt, x1, y1, x2, y2, ang)
  use gtv_interfaces, except_this=> gr8_bltgle
  !---------------------------------------------------------------------
  ! @ private-mandatory (because symbol is used elsewhere)
  !  Support routine for BLTLIS (REAL*8 version)
  !  Returns angle from A through a test position to B
  !  BLTGLE returns the angle in degrees from (X1, Y1) to (XT, YT) to
  ! (X2, Y2).
  !---------------------------------------------------------------------
  real(kind=4), intent(in)  :: xt   ! Test position (X)
  real(kind=4), intent(in)  :: yt   ! Test position (Y)
  real(kind=8), intent(in)  :: x1   ! Mark position 1 (X)
  real(kind=8), intent(in)  :: y1   ! Mark position 1 (Y)
  real(kind=8), intent(in)  :: x2   ! Mark position 2 (X)
  real(kind=8), intent(in)  :: y2   ! Mark position 2 (Y)
  real(kind=4), intent(out) :: ang  ! Angle between 1 -> T -> 2
  ! Local
  real(kind=4) :: xx1, xx2, yy1, yy2, cross, dot
  real(kind=4), parameter :: r2d=57.29578e0
  !
  ! Vector coordinates
  xx1 = x1 - xt
  yy1 = y1 - yt
  xx2 = x2 - xt
  yy2 = y2 - yt
  ! CROSS prop SIN
  ! DOT prop COS
  cross = xx1 * yy2  -  xx2 * yy1
  dot   = xx1 * xx2  +  yy1 * yy2
  ang = 0.0
  if (cross.ne.0. .or. dot.ne.0.) ang = r2d * atan2 (cross, dot)
end subroutine gr8_bltgle
!
subroutine gr4_bltlis(lpoly,llv,npoly,nvert,xv,yv,iy,lnx,ixl,ixu)
  use gtv_interfaces, except_this=>gr4_bltlis
  !---------------------------------------------------------------------
  ! @ public
  ! From a list of polygons, BLTLIS makes a list of horizontal line
  ! segments included in the polygons. There might several segments
  ! to fill for a row crossed by a single polygon.
  !---------------------------------------------------------------------
  integer(kind=4), intent(in)  :: lpoly      ! Beginning polygon number
  integer(kind=4), intent(in)  :: llv        ! Beginning vertex number
  integer(kind=4), intent(in)  :: npoly      ! Number of polygons
  integer(kind=4), intent(in)  :: nvert(2)   ! Number of vertices in each polygon
  real(kind=4),    intent(in)  :: xv(1024)   ! X position of vertices
  real(kind=4),    intent(in)  :: yv(1024)   ! Y position of vertices
  real(kind=4),    intent(in)  :: iy         ! Row number
  integer(kind=4), intent(out) :: lnx        ! Number of segments
  real(kind=4),    intent(out) :: ixl(1024)  ! Low x index of segments
  real(kind=4),    intent(out) :: ixu(1024)  ! High x index of segments
  ! Local
  integer(kind=4) :: lp,ip,lv,nxe,i,j,k
  real(kind=4) :: y1,y2,ix
  logical :: sorted
  integer(kind=4), parameter :: xsegmax=1024  ! Should be greater or equal to ixl/ixu dimension
  real(kind=4) :: rx,ry,ang,angsum,xse(xsegmax)
  !
  lnx = 0
  lp = llv
  ry = iy
  do ip=lpoly,npoly
    lv = nvert(ip) + lp - 2
    ! find intersections
    nxe = 0
    do i=lp,lv
      y1 = yv(i)
      y2 = yv(i+1)
      if (y1.eq.y2) cycle  ! I
      if (iy.lt.y1 .and. iy.lt.y2) cycle  ! I
      if (iy.gt.y1 .and. iy.gt.y2) cycle  ! I
      if (nxe.eq.xsegmax)  cycle  ! Buffers will be exhausted. Silently skip
      nxe = nxe + 1
      xse(nxe) = (xv(i+1)-xv(i)) * (iy-y1) / (y2-y1) + xv(i)
    enddo  ! I
    if (nxe.le.1) go to 70
    !
    ! Sort list (Catastrophically programmed)
    sorted = .false.
    do while (.not.sorted)
      sorted = .true.
      do i = 2,nxe
        if (xse(i-1).gt.xse(i)) then
          rx = xse(i-1)
          xse(i-1) = xse(i)
          xse(i) = rx
          sorted = .false.
        endif
      enddo
    enddo
    !
    ! which are interior
    do i=2,nxe
      rx = (xse(i-1) + xse(i)) / 2.0
      ix = rx
      ! test for on an edge
      do j=lp,lv
        if (iy.ne.yv(j)) go to 35
        if (ix.eq.xv(j)) go to 55
        if (ix.ge.xv(j) .and. ix.le.xv(j+1) .and. iy.eq.yv(j+1))  go to 55
        if (ix.le.xv(j) .and. ix.ge.xv(j+1) .and. iy.eq.yv(j+1))  go to 55
35      if (ix.ne.xv(j))  cycle
        if (iy.ge.yv(j) .and. iy.le.yv(j+1) .and. ix.eq.xv(j+1))  go to 55
        if (iy.le.yv(j) .and. iy.ge.yv(j+1) .and. ix.eq.xv(j+1))  go to 55
      enddo
      !
      angsum = 0.0
      do j = lp,lv
        call gr4_bltgle (rx, ry, xv(j), yv(j), xv(j+1), yv(j+1), ang)
        angsum = angsum + ang
      enddo
      if (abs(angsum).lt.180.) cycle   ! I
55    lnx = lnx + 1
      ixl(lnx) = xse(i-1)
      ixu(lnx) = xse(i)
    enddo                      ! I
70  lp = lv + 2
  enddo                        ! IP
  !
  if (lnx.le.0) go to 999
  !
  ! compress list
  i = 1
85 if (i.ge.lnx) go to 999
  i = i + 1
90 if (ixu(i-1).ne.ixl(i)) go to 85
  j = lnx - i
  ixu(i-1) = ixu(i)
  lnx = lnx - 1
  if (j.le.0) go to 999
  do k=i+1,i+j
    ixl(k-1) = ixl(k)
  enddo
  do k=i+1,i+j
    ixu(k-1) = ixu(k)
  enddo
  go to 90
  !
999 return
end subroutine gr4_bltlis
!
subroutine gr4_bltgle (xt, yt, x1, y1, x2, y2, ang)
  use gtv_interfaces, except_this=> gr4_bltgle
  !---------------------------------------------------------------------
  ! @ private-mandatory (because symbol is used elsewhere)
  !  Support routine for BLTLIS (REAL*4 version)
  !  Returns angle from A through a test position to B
  !  BLTGLE returns the angle in degrees from (X1, Y1) to (XT, YT) to
  ! (X2, Y2).
  !---------------------------------------------------------------------
  real(kind=4), intent(in)  :: xt   ! Test position (X)
  real(kind=4), intent(in)  :: yt   ! Test position (Y)
  real(kind=4), intent(in)  :: x1   ! Mark position 1 (X)
  real(kind=4), intent(in)  :: y1   ! Mark position 1 (Y)
  real(kind=4), intent(in)  :: x2   ! Mark position 2 (X)
  real(kind=4), intent(in)  :: y2   ! Mark position 2 (Y)
  real(kind=4), intent(out) :: ang  ! Angle between 1 -> T -> 2
  ! Local
  real(kind=4) :: xx1, xx2, yy1, yy2, cross, dot
  real(kind=4), parameter :: r2d=57.29578e0
  !
  ! Vector coordinates
  xx1 = x1 - xt
  yy1 = y1 - yt
  xx2 = x2 - xt
  yy2 = y2 - yt
  ! CROSS prop SIN
  ! DOT prop COS
  cross = xx1 * yy2  -  xx2 * yy1
  dot   = xx1 * xx2  +  yy1 * yy2
  ang = 0.0
  if (cross.ne.0. .or. dot.ne.0.) ang = r2d * atan2 (cross, dot)
end subroutine gr4_bltgle
