# Implementation of module {contact}
# Last edited on 2021-03-21 16:02:12 by jstolfi

import contour

import block
import path

import rn

from shapely.geometry import Point
from shapely.geometry.polygon import Polygon

class Contour_IMP:
  def __init__(self, pts, mp_trace_contour, mp_jump):
    self.pts = pts
    self.mp_trace  = mp_trace_contour
    self.mp_jump  = mp_jump
    self.ic = []
    self.oc = []
    self.ib = []
    #
    self.used = False


def make(pts, mp_trace_contour, mp_jump):
  return contour.Contour(pts, mp_trace_contour, mp_jump)
  # ----------------------------------------------------------------------

def get_points(ctr):
  return ctr.pts
  # ----------------------------------------------------------------------
  

def set_in_contour(ctr, ic):
  ctr.ic.append(ic)
  # ----------------------------------------------------------------------
  
def get_in_contour(ctr):
  return ctr.ic
  # ----------------------------------------------------------------------
  

def set_out_contour(ctr, oc):
    ctr.oc.append(oc)
  # ----------------------------------------------------------------------
  # ----------------------------------------------------------------------
  
def get_out_contour(ctr):
  return ctr.oc
  # ----------------------------------------------------------------------
  

def set_blocks(ctr, ib):
  ctr.ib.append(ib)
  # ----------------------------------------------------------------------
  
def get_blocks(ctr):
  return ctr.ib
  # ----------------------------------------------------------------------
  

def find_point (ctr, pt):
  dMin = None
  pMin = None

  for p in ctr.pts:
      d = rn.dist (pt, p)
      if dMin == None or dMin > d:
          dMin = d
          pMin = p
  
  return pMin, dMin
  # ----------------------------------------------------------------------
  
def make_path_temp(ctr):
  pts = ctr.pts 
  pts.append(pts[0])
  return path.from_points(pts, ctr.mp_trace, ctr.mp_jump)
  # ----------------------------------------------------------------------
  
def make_path(ctr, start_point):
  def sort_contour(ctr, start_point):
    pts = ctr.pts
    start_point, d = find_point(ctr, start_point)
    index = pts.index(start_point)
    pts = pts[index:] + pts[:index]
    pts.append(pts[0])
    return pts

  pts = sort_contour(ctr, start_point)
  contour_path = path.from_points(pts, ctr.mp_trace, ctr.mp_jump)
  return contour_path, pts[0]
  # ----------------------------------------------------------------------
  

def set_used(ctr, us):
  ctr.used = us
  # ----------------------------------------------------------------------
  
def used(ctr):
  return ctr.used
  # ----------------------------------------------------------------------


def create_contour(CP, mp_trace_contour, mp_jump):
  CTRS = []
  
  for cp in CP:
    ctr = contour.make(cp, mp_trace_contour, mp_jump)   
    CTRS.append(ctr)
  
  find_external_contour(CTRS)

  return CTRS
  # ----------------------------------------------------------------------

def find_external_contour(CTRS):
  for c1 in CTRS:
    polygon1 = Polygon(contour.get_points(c1))

    for c2 in CTRS:
      if c1 != c2:
        polygon2 = Polygon(contour.get_points(c2))

        if polygon1.contains(polygon2) and polygon2.within(polygon1): # {polygon1} out e {polygon2} in.
          contour.set_in_contour(c1, c2)
          contour.set_out_contour(c2, c1)
  # ----------------------------------------------------------------------
  
def find_contour(CTRS, BS):
  for ctr in CTRS:
    polygon = Polygon(contour.get_points(ctr))

    for bc in BS:
      point = Point(path.pini(block.choice(bc, 0)))

      if (polygon.contains(point)): 
        if len(contour.get_in_contour(ctr)) == 0:
          contour.set_blocks(ctr, bc)

        else:
          in_contour = False

          for in_co in contour.get_in_contour(ctr):
            polygonIn = Polygon(contour.get_points(in_co))

            if (polygonIn.contains(point)):
              in_contour = True
          
          if not in_contour:
            contour.set_blocks(ctr, bc)
  return
  # ----------------------------------------------------------------------


def bbox(CTRS):
  B = None
  for ctr in CTRS:
    ctr_path = contour.make_path_temp(ctr)
    B = rn.box_join(B, path.bbox([ctr_path]))
  assert B != None
  return B
  # ----------------------------------------------------------------------