# Implementation of the module {txt_read}. # Last edited on 2021-10-03 14:49:26 by stolfi import txt_write import block import block_hp import move import move_parms import move_hp import path import path_hp import raster import contact import contact_hp 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, CTS, Z, angle): ncr = len(OCRS) nph = len(OPHS_orig) nct = len(CTS) # 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) sys.stderr.write("writing %d contours, %d rasters, %d contacts\n" % (ncr,nph,nct)) write_rasters(wr, OPHS, xdir) CTS_found = write_contact_and_links(wr, OPHS, xdir, ydir, ystep, yphase) assert set(CTS_found) == set(CTS) if ncr > 0: write_contours(wr, OCRS) 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_hp.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_contact_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_hp.get_contacts}. # # Also writes in that line the geometry of the link paths # between those two rasters, as defined by {path_hp.get_contacts}. # Assumes that {OPHS} is in scanline order and the # scanline positions along {ydir} have separation {ystep} # and phase {yphase}. # # Returns the list {CTS_found} of the {Contact} objects found. debug = False def write_L_line(iph0, iph1, OPHS): # 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_hp.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}. if debug: sys.stderr.write(" -------------------------------------\n") oph0 = OPHS[iph0] CTS0 = set(path_hp.get_contacts(oph0, 1)) # Contacts on upper side of {oph0} mv0, dr0 = move.unpack(path.elem(oph0,0)) oph1 = OPHS[iph1] CTS1 = set(path_hp.get_contacts(oph1, 0)) # Contacts on lower side of {oph1} mv1, dr1 = move.unpack(path.elem(oph1,0)) CTS01 = CTS0 & CTS1 # Contacts between the two rasters. if debug: sys.stderr.write(" R%d (%d upper contacts)\n" % (iph0,len(CTS0))) contact.show_list(sys.stderr, tuple(CTS0), 2) sys.stderr.write(" R%d (%d lower contacts)\n" % (iph1,len(CTS1))) contact.show_list(sys.stderr, tuple(CTS1), 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.pop() # 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") 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, OPHS) if ct != None: CTS_found.append(ct) if debug: sys.stderr.write(" #####################################\n") def get_contact_and_links(iph0, iph1, OPHS): return ct, lk0,lk1 # ...................................................................... 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 # ----------------------------------------------------------------------