# Implementation of module {path_hp}.
# Last edited on 2021-10-04 00:12:28 by stolfi

import path_hp
import path
import move
import contact
import block

def get_contacts(ph):
  assert isinstance(ph, path.Path)
  return ph.ctss
  # ----------------------------------------------------------------------

def clear_contacts(oph):
  ph, dr = path.unpack(oph)
  ph.contacts = ([], [])
  return 
  # ----------------------------------------------------------------------

def add_contact(oph, i, ct):
  ph, dr = path.unpack(oph)
  assert type(i) is int and (i == 0 or i == 1)
  ph.contacts[i].append(ct)
  return  
  # ----------------------------------------------------------------------

def get_contacts(oph, i):
  ph, dr = path.unpack(oph)
  assert type(i) is int and (i == 0 or i == 1)
  return ph.contacts[i]
  # ----------------------------------------------------------------------

def get_block(ph):
  assert isinstance(ph, path.Path)
  return ph.block
  # ----------------------------------------------------------------------
 
def set_block(ph, bc):
  assert isinstance(ph, path.Path)
  assert isinstance(bc, block.Block)
  ph.block = bc
  return  
  # ----------------------------------------------------------------------

def get_blocks_in_contour(cr):
  ph, dr = path.unpack(cr)
  return ph.fill_BCS
  # ----------------------------------------------------------------------

def assign_blocks_to_contours(CRS, BCS):
  
  nbc = len(BCS)
  ncr = len(CRS)

  # Convert each contour {CRS[icr]} to a {shapely} polygon {PGS[icr]}:
  PGS = []
  for cr in CRS:
    PTS_cr = [ move.pini(path.elem(cr, k)) for k in range(path.nelems(cr)) ]
    PGS.append(Polygon(PTS_cr))

  # Get a {shapely} point {PTS[ibc]} on each block:
  PTS_bc = [ Point(path.pini(block.choice(bc, 0))) for bc in BCS ]

  # We will set {icr_inner[ibc]} to the index of the innermost contour that contains {BCS[ibc]}.
  icr_inner = [None]*nbc 
  
  # Scan all contours and all blocks:
  for icr in range(ncr):
    pg = PGS[icr]
    for ibc in range(nbc):
      point = PTS[ibc]
      if (pg.contains(point)): 
        icr_cur = icr_inner[ibc] # Current innermost containg contour.
        if icr_cur == None or pg.contains(PGS[icr_cur]):
          icr_inner[ibc] = icr
        else:
          assert PGS[icr_cur].contains(pg), "contours are not properly nested"
  
  # Now assign blocks to contours:
  for cr in CRS: 
    ph, dr = unpack(cr)
    ph.fill_BCS = []
  for ibc in range(nbc):
    icr = icr_inner[ibc]
    assert icr != None, "block is not inside any contour"
    cr = CRS[icr]
    ph, dr = unpack(cr)
    ph.fill_BCS.append(BCS[ibc])
  return
  # ----------------------------------------------------------------------

