#! /usr/bin/gawk -f # Last edited on 2000-09-06 21:02:30 by stolfi BEGIN { abort = -1; Pi = 3.1415926; if (outName == "") { arg_error(("must define \"outName\"")); } if (straightenStreets == "") { straightenStreets = 1; } # Coordinate transformations: default_transform(); # Coord transformation stack: nsaved = 0; split("", savedM); split("", savedTol); # indexed by trecho id split("", torg); # origin point number split("", tdst); # destination point number split("", tlog); split("", tseq); split("", topp); # Esquinas used in current straight piece of road split("", estraight); nstraight = 0; # Indexed by esquina id split("", ex); split("", ey); split("", ect); split("", enin); split("", etin); # incoming trecho ids split("", enot); split("", etot); # outgoing trecho ids split("", enomrg); # don't-merge flag # Equivalence tree for esquinas (union-find structure) # Indexed by esquina id split("", esqeq); # indexed by logradouro id: split("", gname); split("", gtr); split("", gnt); # indexed by logradouro's name: split("", gmg); # Indexed by EXTERNAL servico number split("", spx); # spx[ms,k] = x of point k of servico ms split("", spy); # spx[ms,k] = y of point k of servico ms split("", snp); # snp[ms] = num points in servico ms split("", scx); # scx[ms] = x of center of servico ms split("", scy); # scx[ms] = y of center of servico ms split("", sname); # sname[ms] = name of servico ms split("", stype); # stype[ms] = type of servico ms split("", slog); # slog[ms,z] = name of logradouro of zth entrance split("", shno); # shno[ms,z] = street number of zth entrance split("", sdir); # sdir[ms,z] = +1 for entrance, -1 for exit, 0 for both split("", snz); # snz[ms] = number of entrances of servico ms efile = ( outName ".esquinas" ); tfile = ( outName ".trechos" ); gfile = ( outName ".logradouros" ); sfile = ( outName ".servicos" ); eplot = ( outName ".eplot" ); tplot = ( outName ".tplot" ); cplot = ( outName ".cplot" ); pplot = ( outName ".pplot" ); ng = 0; nt = 0; ne = 0; ns = 0; melast = -2; # Original file name and line number (before @-expansion): origFileName = "-"; origLineNum = 0; } (abort >= 0) { exit(abort); } /^ *[#][@]/ { # Original file and line number indicator if (NF != 3) { data_error("bad original line indicator command"); } origFileName = $2; origLineNum = $3; next; } // { origLineNum++; } /[#]/ { gsub(/[ ]*[#].*$/, "", $0); } /^ *[!][b]/ { # Save current transformation if (NF != 1) { data_error("bad transformation save commad"); } push_transform(); blocktype = "b"; next; } /^ *[!][e]/{ # Restore saved transformation if (NF != 1) { data_error("bad transformation restore commad"); } pop_transform(); blocktype = "e"; next; } /^ *[!][m][t]/{ # Translation spec if (NF != 3) { data_error("bad translation parameters"); } translate($2, $3); blocktype = "mt"; next; } /^ *[!][m][r]/ { # Rotation spec if (NF != 2) { data_error("bad rotate parameter"); } rotate($2); blocktype = "mr"; next; } /^ *[!][m][s]/ { # Scaling if (NF != 3) { data_error("bad scale parameters"); } scale($2, $3); blocktype = "ms"; next; } /^ *[!][d]/ { # Tolerance spec if (NF != 2) { data_error("bad tolerance parameter"); } Tol = $2; blocktype = "d"; next; } /^ *[!][g]/ { # Logradouro block gsub(/^ *[!][g] */, "", $0); name = trim_spaces($0); printf "\n[%s] ", name > "/dev/stderr"; if (name == "") { data_error("empty logradouro name"); } if (name in gmg) { printf "..." > "/dev/stderr"; mg = gmg[name]; } else { mg = ng; ng++; gname[mg] = name; gmg[name] = mg; gnt[mg] = 0; } melast = -1; dirg = 0; # Both ways. nstraight = 0; straight_esquina = 0; blocktype = "g"; next; } /^ *[!][s]/ { # Servico block gsub(/^ *[!][s] */, "", $0); gsub(/ *[:] */, ":", $0); nfld = split($0, fld, ":"); if (nfld != 2) { data_error("bad servico block"); } name = trim_spaces(fld[1]); type = trim_spaces(fld[2]); printf "\n<%s> ", name > "/dev/stderr"; ms = ns; ns++; sname[ms] = name; snp[ms] = 0; snz[ms] = 0; stype[ms] = type; blocktype = "s"; next; } /^ *[!][z]/ { # Address of a servico if (blocktype != "s") { data_error("address out of place"); } gsub(/^ *[!][z] */, "", $0); gsub(/ *[:] */, ":", $0); nfld = split($0, fld, ":"); if (nfld != 3) { data_error("bad address line"); } name = trim_spaces(fld[1]); hno = trim_spaces(fld[2]); dir = trim_spaces(fld[3]); z = snz[ms]; snz[ms]++; slog[ms,z] = name; shno[ms,z] = hno; sdir[ms,z] = dir; next; } /^ *[!]/{ data_error(("unknown block type [" $0 "]")); } /^ *$/ { # Possibly a break in a road (but preserving the direction) melast = -1; next; } /^ *[-+]*[0-9]/ { # Point record if (NF < 2) { data_error(("bad point format: [" $0 "]")); } x = $1; y = $2; # Transform it: tmpx = x*Ma + y*Mc + Tx; tmpy = x*Mb + y*Md + Ty; x = tmpx; y = tmpy; # Now use it: if (blocktype == "g") { # get flags start_straight_section = 0; end_straight_section = 0; do_not_merge = 0; next_dirg = dirg; for (i = 3; i <= NF; i++) { process_esquina_in_logr_flag($(i)); } # Add esquina add_esquina_to_current_logradouro(x,y); dirg = next_dirg; # straighten out previous esquinas if needed: if (end_straight_section || start_straight_section) { if (end_straight_section) { estraight[nstraight] = melast; nstraight++; if (straightenStreets) { straighten_esquinas(estraight, nstraight); } straight_esquina = 0; } if (start_straight_section) { nstraight = 0; straight_esquina = 1; } } else if (straight_esquina) { estraight[nstraight] = melast; nstraight++; } } else if (blocktype == "s") { # Point of servico's outline if (NF != 2) { data_error(("bad point format: [" $0 "]")); } k = snp[ms]; snp[ms]++; spx[ms,k] = x; spy[ms,k] = y; } else { data_error(("unxpected data point")); } next; } END { if (abort >= 0) { exit(abort); } # reduce_esquinas(); collect_servicos_by_trecho(); write_esquinas_file(); write_trechos_file(); write_logradouros_file(); write_servicos_file(); printf "\n" > "/dev/stderr"; printf "done.\n" > "/dev/stderr"; } function process_esquina_in_logr_flag(flag) { # Parses a flag attached to an esquina point in a logradouro block. # May set the following variables: # # next_dirg = direction of next trecho (+1 forw, -1 backw, 0 two-way) # end_straight_section = true if straight section ends here # start_straight_section = true if straight section starts here # do_not_merge = do not merge with another esquina unless identical # # Direction of next trecho: if (flag == "(u)") { # Sets dont-merge flag do_not_merge = 1; return; } else if (match(flag, /^[(][d].*[)]$/)) { # Sets traffic direction for subsequent trechos. if (flag == "(d+)") { next_dirg = 1; } else if (flag == "(d-)") { next_dirg = -1; } else if (flag == "(d0)") { next_dirg = 0; } else { data_error(("bad direction flag " flag "")); } return; } else if (match(flag, /^[(]s[-+][)]$/)) { # begin/end of straight road section. if (flag == "(s+)") { start_straight_section = 1 } else if (flag == "(s-)") { end_straight_section = 1; } else { data_error(("bad straight section flag " flag "")); } } else { data_error(("bad esquina flag \"" flag "\"")); } } function add_esquina_to_current_logradouro(x,y, mt1,mt2) { # Appends a new esquina to the current logradouro # Global variables used/modified: # # melast = id of last esquina (-1 after a gap, -2 initially) # dirg = direction of traffic (+1 forward, -1 backward, 0 both ways) # mg = id of current logradouro # nstraight = number of trechos in current straight section # do_not_merge = true if esquina should not be merged # Insert in esquinas tables: me = find_esquina_id(x,y,do_not_merge); # Generate trechos: if (melast == -2) { data_error("missing logradouro header"); } if (melast != -1) { mt1 = -1; mt2 = -1; if(dirg >= 0) { mt1 = add_trecho(melast, me, mg); } if(dirg <= 0) { mt2 = add_trecho(me, melast, mg); } if(mt1 != -1) { topp[mt1] = mt2; } if(mt2 != -1) { topp[mt2] = mt1; } } melast = me; } function find_esquina_id(x,y,nomrg, me,wt,xt,yt,dx,dy,d,eps) { # Finds the id of an esquina given its approximate coordinates. # If that fails, adds the esquina to the tables. for (me = 0; me < ne; me++) { xt = ex[me]; yt = ey[me]; dx = x - xt; dy = y - yt; d = sqrt(dx*dx+dy*dy); eps = ((nomrg || enomrg[me]) ? 0 : Tol); if (d <= eps) { # printf "\n%7.1f %7.1f %7.1f %7.1f d = %7.1f me = %d\n", # x, y, xt, yt, d, me > "/dev/stderr"; wt = ect[me]; ect[me]++; ex[me] = ((wt+0.0)*ex[me] + x)/ect[me]; ey[me] = ((wt+0.0)*ey[me] + y)/ect[me]; printf "=" > "/dev/stderr"; return(me); } } me = ne; ne++; ex[me] = x; ey[me] = y; ect[me] = 1; enot[me] = 0; enin[me] = 0; esqeq[me] = me; enomerg[me] = nomrg; printf "!" > "/dev/stderr"; return(me); } function add_trecho(org,dst,mg, seq,r,s) { mt = nt; nt++; # Add to esquina-trecho lists: torg[mt] = org; tdst[mt] = dst; r = enot[org] + 0; enot[org]++; etot[org,r] = mt; s = enin[dst] + 0; enin[dst]++; etin[dst,s] = mt; # Add to logradouro list: tlog[mt] = mg; seq = gnt[mg] + 0; gnt[mg]++; tseq[mt] = seq; gtr[mg,seq] = mt; return(mt); } function find_logradouro_id(name, mg) { # Finds the logradouro ID given the logradouro's name for(mg = 0; mg < ng; mg++) { if (gname[mg] == name) { return(mg); } } error(("bad logradouro name " name)); } function find_trecho_id(name,x,y, mg,mt,seq,org,dst,dx,dy,d,dmin,mtmin) { # Finds the trecho ID given the logradouro's name and # approximate position mg = find_logradouro_id(name); dmin = 9999999; mtmin = -1; for(seq = 0; seq < gnt[mg]; seq++) { mt = gtr[mg,seq]; org = torg[mt]; dst = tdst[mt]; dx = x - (ex[org]+ex[dst])/2.0; dy = y - (ey[org]+ey[dst])/2.0; d = sqrt(dx*dx+dy*dy); if (d < dmin) { dmin = d; mtmin = mt; } } if (mtmin >= 0) { return(mtmin); } error(("logradouro has no trechos " name)); } function straighten_esquinas(estr,nstr, i,eini,efin,ei,ux,uy,ur,vx,vy) { eini = estr[0]; efin = estr[nstr-1]; ux = ex[efin] - ex[eini]; uy = ey[efin] - ey[eini]; ur = sqrt(ux*ux + uy*uy); ux = ux/ur; uy = uy/ur; for(i = 1; i < n-1; i++) { ei = estr[i]; vx = ex[ei] - ex[eini]; vy = ey[ei] - ey[eini]; s = vx*ux + vy*uy; ex[ei] = ex[eini] + s*ux; ey[ei] = ey[eini] + s*ux; } } function default_transform() { Ma = 1; Mb = 0; # Rotation co-sine and sine Mc = 0; Md = 1; # Identity matrix Tx = 0; Ty = 0; # Translation vector Tol = 4; # Tolerance for merging Esquinas } function translate(dx, dy, tmpx, tmpy) { # Apply a translation to all subsequent points BEFORE current transform tmpx = dx * Ma + dy * Mc + Tx; tmpy = dx * Mb + dy * Md + Ty; Tx = tmpx; Ty = tmpy show_transform(); } function rotate(r, rc, rs, Ha, Hb, Hc, Hd) { # Apply a rotation to all subsequent points BEFORE current transform rc = cos(r*Pi/180.0); rs = sin(r*Pi/180.0); Ha = +rc * Ma + rs * Mc; Hb = +rc * Mb + rs * Md; Hc = -rs * Ma + rc * Mc; Hd = -rs * Mb + rc * Md; Ma = Ha; Mb = Hb; Mc = Hc; Md = Hd; show_transform(); } function scale(sx, sy, tmpx, tmpy, rc, rs, tmpc, tmps) { # Apply a scaling transform to all subsequent points BEFORE current transform Ma = sx * Ma; Mb = sx * Mb; Mc = sy * Mc; Md = sy * Md; show_transform(); } function push_transform() { savedM[nsaved,0,0] = Ma; savedM[nsaved,0,1] = Mb; savedM[nsaved,1,0] = Mc; savedM[nsaved,1,1] = Md; savedM[nsaved,2,0] = Tx; savedM[nsaved,2,1] = Ty; savedTol[nsaved] = Tol; nsaved++; } function pop_transform() { if (nsaved == 0) { data_error(("too many pop_transform")); } nsaved--; Ma = savedM[nsaved,0,0]; Mb = savedM[nsaved,0,1]; Mc = savedM[nsaved,1,0]; Md = savedM[nsaved,1,1]; Tx = savedM[nsaved,2,0]; Ty = savedM[nsaved,2,1]; Tol = savedTol[nsaved]; show_transform(); } function show_transform() { printf "\n (M) = (%.4f,%.4f,%.4f,%.4f) (Tx,Ty) = (%.2f,%.2f) Tol = %.1f", Ma, Mb, Mc, Md, Tx, Ty, Tol > "/dev/stderr"; } function collect_servicos_by_trecho() { # Collect servicos by trecho tserv[mt,j] and their directions # tsvdir[mt,j], and define the trechos of that servico str[ms,z]: split("", tnserv); split("", tserv); split("", tsvdir); split("", str); for (mt = 0; mt < nt; mt++) { tnserv[mt] = 0; } for (ms = 0; ms < ns; ms++) { compute_servico_center(ms); for(z = 0; z < snz[ms]; z++) { dir = sdir[ms,z] mt = find_trecho_id(slog[ms,z],scx[ms],scy[ms]); str[ms,z] = mt; jj = tnserv[mt] for(j = 0; j < tnserv[mt]; j++) { if (tserv[mt,j] == ms) { jj = j; } } if (jj == tnserv[mt]) { tserv[mt,jj] = ms; tsvdir[mt,jj] = dir; tnserv[mt]++; } } } } function compute_servico_center (ms, n,k,sx,sy) { n = snp[ms]; sx = 0; sy = 0; for(k = 0; k < n; k++) { sx += spx[ms,k]; sy += spy[ms,k]; } scx[ms] = sx/n; scy[ms] = sy/n; } function trim_spaces(name) { gsub(/^ */, "", name); gsub(/ *$/, "", name); gsub(/ */, " ", name); return(name); } ###################################################################### # Database output function write_esquinas_file() { # Generate "esquinas" file: printf "%4d\n", ne > efile; for (me = 0; me < ne; me++) { printf "%04d : %7.1f %7.1f :", me, ex[me], ey[me] > efile; for (r = 0; r < enin[me]; r++) { printf " %04d", etin[me,r] > efile; } printf " :" > efile; for (s = 0; s < enot[me]; s++) { printf " %04d", etot[me,s] > efile; } printf " :" > efile; for (r = 0; r < enin[me]; r++) for (s = 0; s < enot[me]; s++) { printf " %04d %04d %6.1f", etin[me,r], etot[me,s], 3.0 > efile; } printf "\n" > efile; # Esquinas plot file: printf "%05d %7.1f %7.1f\n", me, ex[me], ey[me] > eplot; } close(efile); close(eplot); } function write_trechos_file() { # Generate "trechos" file, # collect list of incoming/outgoing trechos for each esquina: printf "%4d\n", nt > tfile; for (mt = 0; mt < nt; mt++) { org = torg[mt]; dst = tdst[mt]; # Longitudinal and transversal unit vectors: dx = ex[dst] - ex[org]; dy = ey[dst] - ey[org]; d = sqrt(dx*dx + dy*dy) + 1; dx = dx/d; dy = dy/d; tx = -dy; ty = dx; # Compute plot origin and destination: # If two-way road, shift sideways too: if (topp[mt] == -1) { xorg = ex[org] + 2*dx; yorg = ey[org] + 2*dy; xdst = ex[dst] - 2*dx; ydst = ey[dst] - 2*dy; } else { xorg = ex[org] + 4*dx - 2*tx; yorg = ey[org] + 4*dy - 2*ty; xdst = ex[dst] - 4*dx - 2*tx; ydst = ey[dst] - 4*dy - 2*ty; } # Fake house numbering, bairro, zip code, # num. lanes, car parking bit: tblock = int(tseq[mt]/2); tside = (tseq[mt] % 2); thini = tblock * 100 + tside; thfin = thini + 98; tbairro = 0; tzip = 10000000 + mt; tlanes = 1; tpark = (mt % 2); # Estimate cost: tcost = d; # Print trecho data: printf "%04d", mt > tfile; printf " : %6.1f", tcost > tfile; printf " : %04d : %04d:%04d", tlog[mt], org, dst > tfile; printf " : %d : %4d:%4d", tlanes, thini, thfin > tfile; printf " : %08d : %1d : %03d", tzip, tpark, tbairro > tfile; printf " : %04d :", topp[mt] > tfile; for (j = 0; j < tnserv[mt]; j++) { dir = tsvdir[mt,j]; tag = (dir == 0 ? "" : (dir < 0 ? "-" : "+")); printf " %04d%s", tserv[mt,j], tag > tfile; } printf "\n" > tfile; # Trechos plot file: printf "%05d %7.1f %7.1f\n%05d %7.1f %7.1f\n\n", org, xorg, yorg, dst, xdst, ydst > tplot; } close(tfile); close(tplot); } function write_logradouros_file() { # Generate Logradouros file: printf "%4d\n", ng > gfile; for (mg = 0; mg < ng; mg++) { gtype = 0; printf "%04d : '%s' :", mg, gname[mg] > gfile; for(seq = 0; seq < gnt[mg]; seq++) { printf " %04d", gtr[mg,seq] > gfile; } printf " : %d\n", gtype > gfile; } close(gfile); } function write_servicos_file() { # Generate Servicos file: printf "%4d\n", ns > sfile; for (ms = 0; ms < ns; ms++) { printf "%04d : '%s'", ms, sname[ms] > sfile; if (snz[ms]+0 < 1) { error(("no address for servico " sname[ms])); } printf " : %s : '%s'", find_logradouro_id(slog[ms,0]), shno[ms,0] > sfile; printf " : %7.1f %7.1f :", scx[ms], scy[ms] > sfile; for(k = 0; k < snp[ms]; k++) { printf " %.1f %.1f ", spx[ms,k], spy[ms,k] > sfile; } for (dir = 0; dir < 2; dir++) { # Entrances/exits in direction "dir" printf " :" > sfile; for(z = 0; z < snz[ms]; z++) { if (sdir[ms,z]*dir >= 0) { printf " %05d", str[ms,z] > sfile; } } } printf " : %d\n", stype[ms] > sfile; # Servicos plot files: printf "%04d %7.1f %7.1f\n", ms, scx[ms], scy[ms] > cplot; for(k = 0; k < snp[ms]; k++) { printf "%04d %7.1f %7.1f\n", ms, spx[ms,k], spy[ms,k] > pplot; } printf "%04d %7.1f %7.1f\n", ms, spx[ms,0], spy[ms,0] > pplot; printf "\n" > pplot; } close(sfile); close(cplot); close(pplot); } ###################################################################### # Error reporting function arg_error(msg) { printf "%s\n", msg > "/dev/stderr"; abort = 1; exit(abort); } function data_error(msg) { printf "file %s, line %s: %s\n", origFileName, origLineNum, msg \ > "/dev/stderr"; abort = 1; exit(abort); } function error(msg) { printf "%s\n", msg > "/dev/stderr"; abort = 1; exit(abort); }