# Implementation of the module {txt_read}. # Last edited on 2021-10-10 05:53:32 by stolfi import txt_write import block import move import move_parms import path import raster import contact import hacks import rn import sys from math import sqrt, sin, cos, atan2, log, exp, floor, ceil, inf, nan, pi def write(wr, OCRS, OPHS_orig, Z, angle): ncr = len(OCRS) nph = len(OPHS_orig) # Simple parameters: wr.write("Z%.6f\n" % Z) wr.write("N%d\n" % nph) wr.write("K%d\n" % ncr) # Make copy {OPHS} of {OPHS_orig} sorted by scan-line order: assert nph >= 1 xdir = ( cos(angle), sin(angle) ) ydir = ( -xdir[1], +xdir[0] ) ystep, yphase = raster.get_spacing_and_phase(OPHS_orig, xdir, ydir) OPHS = raster.sort_by_scanline(OPHS_orig, xdir, ydir, ystep, yphase) CTS = set() LKS = set() for oph in OPHS_orig: for dr in range(2): for olk in path.get_links(path.spin(oph, dr)): lki, dri = path.unpack(olk) LKS.add(lki) for isd in range(2): for ct in path.get_contacts(oph,isd) : CTS.add(ct) nct = len(CTS) nlk = len(LKS) sys.stderr.write("writing %d contours, %d rasters, %d contacts, %d links\n" % (ncr,nph,nct, nlk)) write_rasters(wr, OPHS, xdir) if ncr > 0: write_contours(wr, OCRS) if nct > 0 or nlk > 0: write_contacts_and_links(wr, OPHS, xdir, ydir, ystep, yphase) wr.flush() return # ---------------------------------------------------------------------- def write_rasters(wr, OPHS, xdir): # Write the 'R' lines for the rasters in {OPHS}, assumed to be in scanline order.. # As side effect, will reorient the rasters in {OPHS} to point left to right. wr.write("### LINHAS DE RASTER \n") nph = len(OPHS) for iph in range(nph): oph = OPHS[iph] assert path.nelems(oph) == 1 p = path.pini(oph); q = path.pfin(oph); # Write the raster oriented left to right: xp = rn.dot(p, xdir) xq = rn.dot(q, xdir) if xp > xq: p,q = q,p; xp,xq = xq,xp OPHS[iph] = path.rev(OPHS[iph]) rbit = 1 else: rbit = 0 igr = path.get_group(oph) assert igr >= 0 wr.write("R%d,%.6f,%.6f,%.6f,%.6f,%d,%d\n" % (iph, p[0], p[1], q[0], q[1], rbit, igr)) return # ---------------------------------------------------------------------- def write_contacts_and_links(wr, OPHS, xdir, ydir, ystep, yphase): # Writes an 'L' line to {wr} for every pair of # rasters in {OPHS} that are in consecutive scanlines # and make a contact, as defined by {path.get_contacts}. # # Also writes in that line the geometry of the link paths # between those two rasters, as defined by {path.get_links}. # Assumes that {OPHS} is in scanline order and the # scanline positions along {ydir} have separation {ystep} # and phase {yphase}. debug = False def write_L_line(iph0, iph1): # Checks whether there is a contact between raster elements # {OPHS[iph0]} and {OPHS[iph1]}. The elements are assumed to be on # consecutive scanlines, from lower to upper, and oriented in the # same direction. # # If there is a contact (found through {path.get_contacts}), writes the # corresponding 'L' line. If there are link paths between the two # elements, writes their geomery on that line, too. Returns that contact. # # If there is no contact, does not write anything, and returns {None}. debug = True if debug: sys.stderr.write(" -------------------------------------\n") oph0 = OPHS[iph0]; mv0, dr0 = move.unpack(path.elem(oph0,0)) # The bottom raster element as path and move. oph1 = OPHS[iph1]; mv1, dr1 = move.unpack(path.elem(oph1,0)) # The top raster element as path and move. assert path.nelems(oph0) == 1 assert path.nelems(oph1) == 1 if debug: for isd in range(2): ophi = (oph0,oph1)[isd] sys.stderr.write(" oph%d:" % isd) path.show(sys.stderr, ophi, True, 2, 0, 0) sys.stderr.write("\n") CTS0u = path.get_contacts(oph0,1) # Contacts on upper side of {oph0}. CTS1d = path.get_contacts(oph1,0) # Contacts on lower side of {oph1}. CTS01 = CTS0u & CTS1d # Contacts between the two rasters. if debug: CTS0d = path.get_contacts(oph0,0) # Contacts on lower side of {oph0}. CTS1u = path.get_contacts(oph1,1) # Contacts on upper side of {oph1}. sys.stderr.write(" R%d (%d lower, %d upper contacts)\n" % (iph0,len(CTS0d),len(CTS0u))) contact.show_list(sys.stderr, tuple(CTS0d), 2) contact.show_list(sys.stderr, tuple(CTS0u), 2) sys.stderr.write(" R%d (%d lower, %d upper contacts)\n" % (iph1,len(CTS1d),len(CTS0u))) contact.show_list(sys.stderr, tuple(CTS1d), 2) contact.show_list(sys.stderr, tuple(CTS1u), 2) sys.stderr.write(" %d common contacts\n" % len(CTS01)) contact.show_list(sys.stderr, tuple(CTS01), 2) if len(CTS01) == 0: # No contact between the rasters. ct = None elif len(CTS01) == 1: # There is a contact between {oph0} and {oph1}: [ct] = CTS01 # Get that lone contact in {ct}. # Paranoia: mv0_ct = contact.side_move(ct, 0) mv1_ct = contact.side_move(ct, 1) assert mv0_ct != mv1_ct assert mv0_ct == mv0 or mv0_ct == mv1 assert mv1_ct == mv0 or mv1_ct == mv1 # Get the link paths between the two rasters, if any: lk0 = path.get_connecting_link(path.rev(oph0), oph1) xlk0 = encode_link(lk0) lk1 = path.get_connecting_link(oph0, path.rev(oph1)) xlk1 = encode_link(lk1) # Write the contact and links: wr.write("L%d,L%d,%s,%s\n" % (iph0,iph1, xlk0,xlk1)) else: assert False, "More than one contact between two rasters" if debug: sys.stderr.write(" -------------------------------------\n") debug = False return ct # ...................................................................... def encode_link(olk): # Encodes the geometry of the link path {olk} as a # list of points spearated by ';', each point # being two coordinates separated by '&'. # If {olk} is {None}, returns the string 'None' instead. if olk == None: xlk = "None" else: nmv = path.nelems(olk) xlk = "" for ipt in range(nmv+1): mvi = path.elem(olk, min(ipt,nmv-1)) pti = move.pini(mvi) if ipt < nmv else move.pfin(mvi) xlk += (";" if ipt > 0 else "") + ("%.6f&%.6f" % (pti[0], pti[1])) return xlk # ...................................................................... # Write links and contacts between adjacent rasters: wr.write("### LINHAS ADJACENTES \n") SCS = raster.separate_by_scanline(OPHS, xdir, ydir, ystep, yphase) CTS_found = [] nsc = len(SCS) # Number of scanlines (including empty ones) for isc in range(nsc-1): SC0 = SCS[isc] # List of indices of rasters in scanline {isc}. SC1 = SCS[isc+1] # List of indices of rasters in scanline {isc+1}. if debug: sys.stderr.write(" #####################################\n") sys.stderr.write(" scanlines %d %s and %d %s\n" % (isc,str(SC0),isc+1,str(SC1))) for iph0 in SC0: for iph1 in SC1: ct = write_L_line(iph0, iph1) if ct != None: CTS_found.append(ct) if debug: sys.stderr.write(" #####################################\n") return CTS_found # ---------------------------------------------------------------------- def write_contours(wr, OCRS): # Write to {wr} the contours in {OCRS}, as a bunch of 'C' lines. wr.write("### CONTORNOS \n") ncr = len(OCRS) # Number of contour components. for icr in range(ncr): ocr = OCRS[icr] for ipt in range(path.nelems(ocr)): p = move.pini(path.elem(ocr, ipt)) wr.write("C%d,%.6f,%.6f\n" % (icr, p[0], p[1])) return # ----------------------------------------------------------------------