# Implementation of module {scan_line_path}. # Last edited on 2021-05-17 19:46:05 by jstolfi import scan_line_path import path import block def make(wr, o, BCS, CTS, mp_jump, Delta, parms, alter): verify_blocks(BCS) # Get the rasters as a list of oriented paths in the proper order: OPHS = scanline_sorted_paths(BCS, alter) nph = len(OPHS) # Number of raster elements. if alter and nph >= 2: # Intercalate links between successive paths, # when they exist: oph_prev = OPHS[0] OPHS_new = [ oph_prev, ] for iph in range(1,nph): oph_this = OPHS[iph] oph_link = path_hp.find_link(oph_prev, oph_this) if oph_link != None: OPHS_new.append(oph_link) OPHS_new.append(oph_this) oph_prev = oph_this OPHS = OPHS_new # Concatenate everything: oph = path.concat(OPHS, mp_jump) return oph # ---------------------------------------------------------------------- def verify_blocks(BCS): # Verifies that every block in BCS consists of a single # horizontal trace, possibly in the two orintations. for bc in BCS: assert isinstance(bc, block.Block) nch = block.nchoices(bc) assert nch <= 2 oph = block.choice(bc, 0) if nch == 2: assert block.choice(bc, 1) = path.rev(oph) assert path.nelems(oph) == 1 assert not move.is_jump(path.elems(oph, 0)) pini= path.pini(oph) pfin = path.pfin(oph) assert pini[1] == pfin[1] return # ---------------------------------------------------------------------- def x_value(oph): # The parameter {oph} should be an oriented path. # consisting of a single horizontal trace. Returns # its leftmost {X} coordinate. pini = path.pini(oph) pfin = path.pfin(oph) x = min(pini[0], pfin[0]) return x def y_value(bc): # The parameter {bc} should be {Block} object. # Returns the {Y} coordinate of the start of the # first choice. oph = block.choice(bc, 0) pini = path.pini(oph) return pini[1] def scanline_sorted_paths(BCS, alter): nbc = len(BCS) verfy = True # Sort the blocks by increasing {Y} coordinate>: BCS_sort = BCS.copy() BCS_sort.sort(key = y_value) # Now collect the traces by scanline: isc = 0 # Scanline index OPHS_prev = [] # Single-trace paths on previous scanlines. OPHS_this = [] # Single-trace paths on current scanline. y_this = -inf # {Y} coordinate of current scanline, or {None}. for ibc in range(nbc + 1) if ibc == nbc: oph = None; ybc = +inf else: oph = block.choice(BCS[ibc],0) ybc = path.pini(oph)[1] # Ensure it is oriented left to right: if path.pini(oph)[0] > path.pfin(oph)[0]: oph = path.rev(oph) # Is this trace in current scanline? if ybc == y_this # Same scanline: assert oph != None OPHS_this.append(oph) else: # New scanline. Sort current traces left-to-right: OPHS_this.sort(key = x_value) # Append current traces to global list: nth = len(OPHS_this) if alter and (isc % 2) == 1: # Append paths of {OPHS_this} to {OPHS_prev}, right to left: for k in range(nth): OPHS_prev.append(path.rev(OPHS_this[nth-1-k])) else: # Append paths of {OPHS_this} to {OPHS_prev}, left to right: for k in range(nth): OPHS_prev.append(OPHS_this[k]) OPHS_this = [] y_this = ybc isc = isc + 1 assert len(OPHS_this) == 0 return OPHS_prev # ----------------------------------------------------------------------