#!/bin/sh ############################################################################ # # MODULE: d.frontline # AUTHOR(S): Alexander Muriy # (Institute of Environmental Geoscience, Moscow, Russia) # e-mail: amuriy AT gmail DOT com # # PURPOSE: Displays frontlines on the graphic monitor using d.graph # (optionally save graph file and ps.map file) # # COPYRIGHT: (C) 05-06/2011 Alexander Muriy / GRASS Development Team # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # ############################################################################ #%Module #% description: Display different types of frontlines on the graphic monitor using d.graph (optionally save graph file and ps.map file) #% keywords: display, graphics, vector, symbology #%End #%Option #% key: map #% type: string #% required: yes #% multiple: no #% key_desc: name #% description: Name of input vector map #% gisprompt: old,vector,vector #% guisection: Select #%End #%Option #% key: where #% type: string #% description: The WHERE statement for data filtering #% label: WHERE conditions of SQL query statement without 'where' keyword #% required : no #% guisection: Select #%End #%Option #% key: hcolor #% type: string #% description: Standard color name or R:G:B #% label: Highlight color for vector interactive selecting #% required : no #% answer: yellow #% gisprompt: old_color,color,color #% guisection: Select #%End #%Option #% key: list #% type: string #% description: Example: 1,3,7-9,13 #% label: Category number(s) #% required : no #% guisection: Select #%End #%Option #% key: layer #% type: integer #% label: Layer number. If -1, all layers are extracted. #% description: A single vector map can be connected to multiple database tables. This number determines which table to use. #% required : no #% answer: 1 #% guisection: Select #%End #%Option #% key: side #% type: string #% description: Side of the frontline #% options: left,right,both #% answer: left #%End #%Option #% key: interval #% type: double #% required: yes #% description: Interval between symbols (in mapset units) #%End #%Option #% key: symbol #% type: string #% required: yes #% multiple: no #% description: Type of symbol (<front/...> symbols will be produced by script at first use: front/arrow_int, front/arrow_ext, front/box, front/circle, front/half_box, front/line, front/triangle). May be any symbol from $GISBASE/etc/symbol/ or $MAPSET/symbol/ directories. #% guisection: Symbol #%End #%Option #% key: size #% type: integer #% required: no #% description: Symbol size #% answer: 20 #% guisection: Symbol #%End #%Option #% key: line_color #% type: string #% required: no #% description: Color for line (standard color name or R:G:B) #% answer: black #% gisprompt: old_color,color,color #% guisection: Symbol #%End #%Option #% key: fill_color #% type: string #% required: no #% description: Color for fill (standard color name or R:G:B) #% answer: grey #% gisprompt: old_color,color,color #% guisection: Symbol #%End #%Option #% key: width #% type: integer #% required: no #% description: Width of symbol's line #% answer: 0 #% guisection: Symbol #%End #%Option #% key: graph #% type: string #% required: no #% multiple: no #% key_desc: name #% description: Output file to save the d.graph commands #% gisprompt: new_file,file,output #%End #%Option #% key: psmap #% type: string #% required: no #% multiple: no #% key_desc: name #% description: Output file to save the ps.map commands #% gisprompt: new_file,file,output #%End #%Flag #% key: m #% description: Select vector features interactively (with a mouse) #% guisection: Select #%End #%Flag #% key: s #% description: Save graphics commands in file(s) (for use with d.graph and/or ps.map) #%End if [ -z "$GISBASE" ] ; then echo "You must be in GRASS GIS to run this program." 1>&2 exit 1 fi if [ "$1" != "@ARGS_PARSED@" ] ; then exec g.parser "$0" "$@" fi ## set environment so that awk works properly in all languages ## unset LC_ALL export LC_NUMERIC=C ############################################################ cleanup() { g.mremove -f vect="TMP*" --quiet \rm -f $TMP1* $TMP2* $TMP3* $TMP4* $TMP5* } ############################################################ ## what to do in case of user break: exitprocedure() { echo "User break!" cleanup exit 1 } ## shell check for user break (signal list: trap -l) trap "exitprocedure" 2 3 15 ############################################################ ## check for awk if [ ! -x "$(which awk)" ] ; then g.message -e "awk required, please install awk or gawk first" exit 1 fi ## does map exist? eval "$(g.gisenv)" eval "$(g.findfile mapset="$MAPSET" element=vector file="$GIS_OPT_MAP")" if [ ! "$file" ]; then g.message -e "Vector map <"$GIS_OPT_MAP"> not found" exit 1 fi ## check for lines and boundaries in input map eval "$(v.info -t "$GIS_OPT_MAP")" if [ "$lines" -eq 0 ] && [ "$boundaries" -eq 0 ]; then g.message -e "Input vector map not contain lines or boundaries" exit 1 fi # for vars in "$(v.info -t "$GIS_OPT_MAP" | cut -d"=" -f1)"; do # unset -v "$vars" # done ## check if monitor started if [ "$(d.mon -p | cut -f1 -d' ')" != "Currently" ] ; then g.message -e "No active monitors. Please start <d.mon ...> first" exit 1 fi ## check for "-m" flag and "where" option if [ "$GIS_FLAG_M" -eq 1 ] && [ -n "$GIS_OPT_WHERE" -o -n "$GIS_OPT_LIST" ]; then g.message -e "Please choose only one of selection methods: interactive (flag <"-m">) OR non-interactive -- (<"where"> statement or <"list"> of category values )" exit 1 fi ## check for "list" and "where" options if [ -n "$GIS_OPT_WHERE" ] && [ -n "$GIS_OPT_LIST" ]; then g.message -e "Please choose only one of non-interactive selection methods: <"where"> statement or <"list"> of category values" exit 1 fi ## is input vector displayed now ? d.save -oc | grep -e "d.vect map=" | cut -d'"' -f2 | grep -e "$GIS_OPT_MAP" --quiet if [ "$?" -eq 1 ]; then g.message -e "Input vector map <""$GIS_OPT_MAP""> is not on the monitor. Please use <d.vect "$GIS_OPT_MAP" ..> to display it" exit 1 fi ############################################################ ## setup temporary files ## # create temporary file for segments azimuth TMP1="$(g.tempfile pid=$$)" if [ "$?" -ne 0 ] || [ -z "$TMP1" ] ; then g.message -e "ERROR: Unable to create temporary files." exit 1 fi # create temporary file for symbols' points coordinates TMP2="$(g.tempfile pid=$$)" if [ "$?" -ne 0 ] || [ -z "$TMP2" ] ; then g.message -e "ERROR: Unable to create temporary files." exit 1 fi # create temporary file for points to lines query TMP3="$(g.tempfile pid=$$)" if [ "$?" -ne 0 ] || [ -z "$TMP3" ] ; then g.message -e "ERROR: Unable to create temporary files." exit 1 fi # create temporary file for d.graph commands file TMP4="$(g.tempfile pid=$$)" if [ "$?" -ne 0 ] || [ -z "$TMP4" ] ; then g.message -e "ERROR: Unable to create temporary files." exit 1 fi # create temporary file for d.graph commands file TMP5="$(g.tempfile pid=$$)" if [ "$?" -ne 0 ] || [ -z "$TMP4" ] ; then g.message -e "ERROR: Unable to create temporary files." exit 1 fi # create temporary file for psmap file TMP6="$(g.tempfile pid=$$)" if [ "$?" -ne 0 ] || [ -z "$TMP5" ] ; then g.message -e "ERROR: Unable to create temporary files." exit 1 fi ############################################################ ## vector selecting if [ "$GIS_FLAG_M" -eq 1 ]; then echo "Select vector(s) with mouse - L: draw box with left mouse button to select - M: draw box with middle mouse button to remove from display - R: quit and save selected vectors to new map" d.extract input="$GIS_OPT_MAP" output=TMP_select type=line,boundary hcolor="$GIS_OPT_HCOLOR" --quiet elif [ "$GIS_FLAG_M" -eq 0 -a -z "$GIS_OPT_WHERE" -a -z "$GIS_OPT_LIST" ]; then g.copy vect="$GIS_OPT_MAP",TMP_select --quiet fi if [ -n "$GIS_OPT_WHERE" ]; then v.extract -t input="$GIS_OPT_MAP" output=TMP_select type=line,boundary where="$GIS_OPT_WHERE" layer="$GIS_OPT_LAYER" --quiet elif [ -n "$GIS_OPT_LIST" ]; then v.extract -t input="$GIS_OPT_MAP" output=TMP_select type=line,boundary list="$GIS_OPT_LIST" layer="$GIS_OPT_LAYER" --quiet fi ## TODO: maybe use v.segment for more precise segments splitting ??? ## In that case --> generate split-file with points for v.segment with v.to.db ## (line length) and AWK ## bounds to lines (if needed) eval "$(v.info -t TMP_select)" if [ "$boundaries" -ne 0 ]; then v.type input=TMP_select output=TMP_select_lines type=boundary,line --quiet else g.rename vect=TMP_select,TMP_select_lines --quiet fi # for vars in "$(v.info -t TMP_select_lines | cut -d"=" -f1)"; do # unset -v "$vars" # done ## split line into segments; delete old cats, add new cats v.split input=TMP_select_lines output=TMP_select_lines_split vertices=2 --quiet > /dev/null v.category input=TMP_select_lines_split output=TMP_select_lines_split_catdel option=del --quiet v.category input=TMP_select_lines_split_catdel output=TMP_select_lines_split_catdel_cats option=add step=1 --quiet SEGM=TMP_select_lines_split_catdel_cats ## find azimuth of each segment in a line or boundary v.to.db -p map="$SEGM" option=azimuth --quiet >> "$TMP1" ## take points for future symbols v.to.points -t -i input=TMP_select_lines type=line dmax="$GIS_OPT_INTERVAL" output=TMP_pts --quiet ## take coordinates of points v.to.db -p map=TMP_pts layer=2 option=coor --quiet >> "$TMP2" ## points to segments' categories query v.distance -p from=TMP_pts to="$SEGM" from_layer=2 to_type=line,boundary upload=cat column=dummy_nearest_cats --quiet >> "$TMP3" awk 'NR>1 {print $0}' "$TMP3" | tr '|' ' ' > "$TMP3.clean" ## awk -F"|" 'BEGIN { OFMT="%.6f" } {print $1,$2,$3}' "$TMP2" >> "$TMP2.pts.coor" join -j 1 "$TMP2.pts.coor" "$TMP3.clean" > "$TMP2.pts.segm" ## find angles of symbols left_front() { awk -F"|" 'BEGIN { OFMT="%.0f" } {print $1,450-$2}' "$TMP1" > "$TMP1.left.angle" awk 'NR==FNR{a[$1]=$2;next}$4 in a{$4=a[$4]}1' "$TMP1.left.angle" "$TMP2.pts.segm" > "$TMP1.left.table" awk '{print "'"rotation"'", $4, "'"symbol $GIS_OPT_SYMBOL"'", "'"$GIS_OPT_SIZE"'", $2, $3, "'"$GIS_OPT_LINE_COLOR"'", "'"$GIS_OPT_FILL_COLOR"'", "'"width"'", "'"$GIS_OPT_WIDTH"'"}' "$TMP1.left.table" >> "$TMP4" if [ -n "$GIS_OPT_PSMAP" ]; then awk '{print "'"point"'", $2, $3, "'"color $GIS_OPT_LINE_COLOR"'", "'"fcolor $GIS_OPT_FILL_COLOR"'", "'"symbol $GIS_OPT_SYMBOL"'", "'"size $GIS_OPT_SIZE"'", "'"rotate"'", $4, "'"end"'"}' "$TMP1.left.table" >> "$TMP6" fi } right_front() { awk -F"|" 'BEGIN { OFMT="%.0f" } {print $1,270-$2}' "$TMP1" > "$TMP1.right.angle" awk 'NR==FNR{a[$1]=$2;next}$4 in a{$4=a[$4]}1' "$TMP1.right.angle" "$TMP2.pts.segm" > "$TMP1.right.table" awk '{print "'"rotation"'", $4, "'"symbol $GIS_OPT_SYMBOL"'", "'"$GIS_OPT_SIZE"'", $2, $3, "'"$GIS_OPT_LINE_COLOR"'", "'"$GIS_OPT_FILL_COLOR"'", "'"width"'", "'"$GIS_OPT_WIDTH"'"}' "$TMP1.right.table" >> "$TMP4" if [ -n "$GIS_OPT_PSMAP" ]; then awk '{print "'"point"'", $2, $3, "'"color $GIS_OPT_LINE_COLOR"'", "'"fcolor $GIS_OPT_FILL_COLOR"'", "'"symbol $GIS_OPT_SYMBOL"'", "'"size $GIS_OPT_SIZE"'", "'"rotate"'", $4, "'"end"'"}' "$TMP1.right.table" >> "$TMP6" fi } case "$GIS_OPT_SIDE" in left) left_front ;; right) right_front ;; both) left_front right_front ;; *) esac ## make custom front symbols in the user's mapset ($MAPSET/symbol/type/name) ??? echo "VERSION 1.0 BOX -0.5 -0.5 1.5 1.5 STRING LINE 0 0 0 1.5 END END STRING LINE 0.4 0.75 0 0 END END STRING LINE -0.4 0.75 0 0 END END" > "$TMP5.arrow.int" echo "VERSION 1.0 BOX -0.5 -0.5 1.5 1.5 STRING LINE 0 0 0 1.5 END END STRING LINE 0.4 0.75 0 1.5 END END STRING LINE -0.4 0.75 0 1.5 END END" > "$TMP5.arrow.ext" echo "VERSION 1.0 BOX -0.5 -0.5 0.5 0.5 POLYGON RING LINE -0.2 0 -0.2 0.4 0.2 0.4 0.2 0 END END END" > "$TMP5.box" echo "VERSION 1.0 BOX -0.5 -0.5 0.5 0.5 POLYGON RING ARC 0 0 0.333 0 180 END END" > "$TMP5.circle" echo "VERSION 1.0 BOX -0.5 -0.5 0.5 0.5 POLYGON RING LINE -0.2 0 -0.2 0.2 0.2 0.2 0.2 0 END END END" > "$TMP5.half_box" echo "VERSION 1.0 BOX -0.5 -0.5 0.5 0.5 STRING LINE 0 0 0 0.5 END END" > "$TMP5.line" echo "VERSION 1.0 BOX -0.5 -0.5 0.5 0.5 POLYGON RING LINE -0.25 0 0 0.5 0.25 0 END END END" > "$TMP5.triangle" eval "$(g.gisenv)" symbol_path="$GISDBASE"/"$LOCATION_NAME"/"$MAPSET"/symbol/front if [ ! -d "$symbol_path" ]; then mkdir -p "$symbol_path" cp -f "$TMP5.arrow.int" "$symbol_path"/arrow_int cp -f "$TMP5.arrow.ext" "$symbol_path"/arrow_ext cp -f "$TMP5.box" "$symbol_path"/box cp -f "$TMP5.circle" "$symbol_path"/circle cp -f "$TMP5.half_box" "$symbol_path"/half_box cp -f "$TMP5.line" "$symbol_path"/line cp -f "$TMP5.triangle" "$symbol_path"/triangle fi ## format d.graph input file and ps.map points file awk '{print $1,$2,"'"\n"'",$10,$11,"'"\n"'",$3,$4,$5,$6,$7,$8,$9}' "$TMP4" >> "$TMP4.fmt" awk '{print $1,$2,$3,"'"\n"'",$4,$5,"'"\n"'",$6,$7,"'"\n"'",$8,$9,"'"\n"'",$10,$11,"'"\n"'",$12,$13,"'"\n"'","'"end"'"}' "$TMP6" >> "$TMP6.fmt" ## draw frontlines and (optionally) save graph file and psmap file if [ "$GIS_FLAG_S" -eq 0 ] && [ -n "$GIS_OPT_GRAPH" ]; then g.message -e "Please use flag <"-s"> to save line graphics in file <"$GIS_OPT_GRAPH">" cleanup exit 1 fi if [ "$GIS_FLAG_S" -eq 1 ]; then if [ -n "$GIS_OPT_GRAPH" ]; then cp -f "$TMP4.fmt" "$GIS_OPT_GRAPH" d.graph -m input="$GIS_OPT_GRAPH" color=none else SYMBOL="$(echo $GIS_OPT_SYMBOL | tr '/' '_')" GRAPH_FILE=""$GISDBASE"/"$LOCATION_NAME"/"$GIS_OPT_MAP"__"$SYMBOL"_"$GIS_OPT_INTERVAL"_"$GIS_OPT_SIDE"_"$GIS_OPT_LINE_COLOR"".graph # cp -f "$TMP4.fmt" "$GRAPH_FILE" cat "$TMP4.fmt" >> "$GRAPH_FILE" d.graph -m input="$GRAPH_FILE" color=none fi else d.graph -m input="$TMP4.fmt" color=none fi if [ "$GIS_FLAG_S" -eq 0 ] && [ -n "$GIS_OPT_PSMAP" ]; then g.message -e "Please use flag <"-s"> to save line graphics in file <"$GIS_OPT_PSMAP"> for use with ps.map" cleanup exit 1 fi if [ -n "$GIS_OPT_PSMAP" ]; then # cp -f "$TMP6.fmt" "$GIS_OPT_PSMAP" cat "$TMP6.fmt" >> "$GIS_OPT_PSMAP" fi cleanup exit 0