# Implementation of the module {block}. # Last edited on 2021-02-19 14:50:19 by jstolfi import block import path import move import contact import hacks import rn import pyx import sys from math import sqrt, floor, ceil, sin, cos, acos, pi, nan, inf class Block_IMP: # A {Block_IMP} object {bc} has a list {bc.ochs} of {nch} one or more oriented # paths that are the choices. def __init__(self, ochs ): self.ochs = ochs def from_paths(ochs): assert type(ochs) == list or type(ochs) == tuple assert len(ochs) > 0 bc = block.Block(tuple(ochs)) return bc def nchoices(bc): assert isinstance(bc, block.Block) n = len(bc.ochs) return n def choice(bc, ip): assert isinstance(bc, block.Block) n = len(bc.ochs) assert ip >= 0 and ip < n och = bc.ochs[ip] # Choice of the elements before reversal. return och def pick(bcp): bc, ip = unpack(bcp) return choice(bc, ip) def unpack(bcp): assert type(bcp) is tuple assert len(bcp) == 2 bc, ip = bcp assert isinstance(bc, block.Block) n = len(bc.ochs) assert type(ip) is int assert ip >= 0 and ip < n return bc, ip def bbox(bc): B = None np = nchoices(bc) for ip in range(np): ophi = choice(bc, ip) Bi = path.bbox(ophi) B = rn.box_join(B, Bi) assert B != None return B # ---------------------------------------------------------------------- def min_extime(bc): assert isinstance(bc, block.Block) n = len(bc.ochs) mex = +inf for k in range(n): ophk = bc.ochs[k] texk = path.extime(ophk) if texk < mex: mex = texk return mex def has_move(bc, mv): n = nchoices(bc) for k in range(n): ophk = choice(bc, k) if path.find(ophk, mv) != None: return True return False #---------------------------------------------------------------------- def validate(bcp): if isinstance(bcp, block.Block): # Convenience - handle naked {Block} too: bc = bcp; ip = 0 else: # Unpack it: bc, ip = unpack(bcp) n = len(bc.ochs) assert n >= 1 # sys.stderr.write("--- validating bcp = %s n = %d ----------\n" % (str(bcp), n)) # Validate the list of choices: for och in bc.ochs: ph, dr = path.unpack(och) # Typechecking. nmv = path.nelems(ph) assert nmv > 0 assert not move.is_jump(path.elem(ph,0)) assert not move.is_jump(path.elem(ph,nmv-1)) def plot(c, bc, org, waxes, axes, dots, arrows, matter): ncolors = 17 colors = hacks.colors_RGB(ncolors) # Colors to use for different layers. np = block.nchoices(bc) # Get the block's bounding box: bcbox = block.bbox(bc) # Get the lower corner and size of each choice sub-plot: plo = (floor(bcbox[0][0])-1, floor(bcbox[0][1])-1) phi = (ceil(bcbox[1][0])+1, ceil(bcbox[1][1])+1) szx = phi[0] - plo[0] szy = phi[1] - plo[1] # Plot one choice from each block: for ip in range(np): ic = ip % ncolors ctraces = colors[ic] orgi = rn.add(org, (0, ip*szy)) ophi = block.choice(bc, ip) hacks.plot_grid(c, None, 0.03, rn.add(orgi,plo), szx, szy, 0.25, 1, 1) layer = None # All layers. path.plot_standard \ ( c, ophi, orgi, layer, ctraces = ctraces, waxes = waxes, axes = axes, dots = dots, arrows = arrows, matter = matter ) return # ---------------------------------------------------------------------- def print_contact_table(wr, BS, CS, MS): nbc = len(BS) nct = len(CS) nmv = (0 if MS == None else len(MS)) def fmt1(i, c, n): fmt = c + "%0" + ("2" if n < 100 else "3")+ "d" return fmt % i def fmt2(i, j, c, n): fmt = c + "%0" + ("2" if n < 100 else "3")+ "d:%d" return fmt % (i,j) # Table header: ctsp = " "*len(fmt2(0,0, "C", nct)) mvsp = " "*len(fmt1(0, "M", nmv)) bcds = "-"*len(fmt2(0,0, "B", nbc)) wr.write("%s %s " % (ctsp,mvsp)) for ib in range(nbc): bci = BS[ib] npi = block.nchoices(bci) for jpi in range(npi): wr.write(" " + (fmt2(ib,jpi, "B", nbc))) wr.write("\n") for i in range(nct): cti = CS[i] for j in range(2): ctID = fmt2(i, j, "C", nct) mvij = contact.side(cti,j) if MS == None: mvID = mvsp else: r = MS.index(mvij) mvID = fmt1(r, "M", nmv) wr.write("%s %s " % (ctID,mvID)) for k in range(nbc): bck = BS[k] npk = block.nchoices(bck) for l in range(npk): ophkl = block.choice(bck, l) t = path.find(ophkl, mvij) if t == None: wr.write(" " + bcds) else: wr.write(" %*d" % (len(bcds), t)) wr.write("\n") wr.write("\n") return # ---------------------------------------------------------------------- def create_test_data(parms): wd = parms['solid_raster_width'] # Make some test moves: p00 = (1,3) p01 = (3,3) mv0 = move.make(p00, p01, wd, parms) p10 = (2,4) p11 = (5,4) mv1 = move.make(p10, p11, wd, parms) p20 = (4,3) p21 = (5,1) mv2 = move.make(p20, p21, wd, parms) dp3 = (sqrt(5)/2, 0) p30 = tuple(rn.add(p20, dp3)) p31 = tuple(rn.add(p21, dp3)) mv3 = move.make(p30, p31, wd, parms) p40 = (5,5) p41 = (6,5) mv4 = move.make(p40, p41, wd, parms) p50 = (3,6) p51 = (4,6) mv5 = move.make(p50, p51, wd, parms) p60 = (3,2) p61 = p60 mv6 = move.make(p60, p61, wd, parms) # Zero-length move. p70 = (2,7) p71 = (4,7) mv7 = move.make(p70, p71, wd, parms) # p80 = (5,7) p81 = (7,7) mv8 = move.make(p80, p81, wd, parms) # p90 = (3,8) p91 = (6,8) mv9 = move.make(p90, p91, wd, parms) # MS = [ mv0, mv1, mv2, mv3, mv4, mv5, mv6, mv7, mv8, mv9 ] # Make jumps between those moves: jm06 = move.make(p01, p60, 0, parms) jm25 = move.make(p20, p50, 0, parms) jm54 = move.make(p51, p40, 0, parms) jm13 = move.make(p11, p30, 0, parms) jm78 = move.make(p71, p80, 0, parms) # Join the moves in paths: opha = path.from_moves((mv0,jm06,mv6,)) ophb = path.from_moves((move.rev(mv2),jm25,mv5,jm54,mv4,)) ophc = path.rev(path.from_moves((mv1,jm13,mv3))) ophd = path.from_moves((mv7,jm78,mv8,)) ophe = path.from_moves((mv9,)) PS = [ opha, ophb, ophc, ophd, ophe ] # Make some contacts between those moves: q00 = (2.0, 3.5) q01 = (3.0, 3.5) ct0 = contact.make(q00, q01, mv0, mv1, parms) q10 = (4.0, 3.5) q11 = q10 ct1 = contact.make(q10, q11, mv1, mv2, parms) q20 = (3.5, 3.0) q21 = (3.5, 3.0) ct2 = contact.make(q20, q21, mv0, mv2, parms) dq3 = (1.0/sqrt(5), 0.5/sqrt(5)) q30 = tuple(rn.sub(p30, dq3)) q31 = tuple(rn.add(p21, dq3)) ct3 = contact.make(q30, q31, mv2, mv3, parms) q40 = (5.0, 4.5) q41 = (5.0, 4.5) ct4 = contact.make(q40, q41, mv0, mv4, parms) q50 = (3.0, 7.5) q51 = (4.0, 7.5) ct5 = contact.make(q50, q51, mv7, mv9, parms) q60 = (5.0, 7.5) q61 = (6.0, 7.5) ct6 = contact.make(q60, q61, mv8, mv9, parms) CS = [ ct0, ct1, ct2, ct3, ct4, ct5, ct6 ] bc0 = block.from_paths([PS[0], path.rev(PS[0]), PS[4], path.rev(PS[4])]) oph12 = path.concat([PS[1], PS[2]], jumps=True, parms=parms) oph21 = path.concat([PS[2], PS[1]], jumps=True, parms=parms) bc1 = block.from_paths([oph12, path.rev(oph12), oph21, path.rev(oph21)]) bc2 = block.from_paths([PS[3], path.rev(PS[3])]) BS = [ bc0, bc1, bc2, ] return MS, PS, CS, BS # ----------------------------------------------------------------------