LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 01-23-2011, 05:29 AM   #1
gary_in_springhill
Member
 
Registered: Mar 2008
Posts: 136

Rep: Reputation: 21
math help in awk to pivot xy coordinates


I'm trying to get 3 awk scripts done to pivot a region (using the center of min-max values as pivot point) 90 180 270 degrees the contents of a xy file.
It works almost (it rotates but location is off) but my math calcs are off along with my math skills.
The minmax are supplied by another script and read as follows
minx=9356
maxx=11388
miny=5191
maxy=7682

the awk script
Code:
BEGIN {
    RS="[;\n\r]";
    FS="[, \t]+";
}

/[[:space:]]*(PU|PD)[-[:digit:]]+/  { 
    cmd = substr($1,1,2);
    x = substr($1,3) + 0;
    y = $2 + 0;
    diffx = maxx - minx;
    diffy = maxy - miny;
    newx = maxy - (diffy / 2);  ### / 2); ###- (miny/2); ######+ (maxx-miny)/2;
    newy = maxx + (diffx / 2); ###- (maxx/2); ####+(maxy-minx)/2;

    printf("%s%d,%d;",cmd,newx,newy);
    next;
}

{
    if( $1 != "" ) {
	printf("%s;\n", $0);
    }
}
I guess I need a variation for 90, 180, and 270 in separate awk scripts.

Thanks
Attached Thumbnails
Click image for larger version

Name:	image.png
Views:	22
Size:	53.6 KB
ID:	5921  
 
Old 01-23-2011, 06:20 AM   #2
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
If the script is fed minx, miny, maxx, maxy, and rotation (in degrees counterclockwise) as variables, put this in the BEGIN section
Code:
rotation = rotation % 360.0
radians = rotation * 3.14159265358979323846 / 180.0
sinr = sin(radians)
cosr = cos(radians)
midx = (minx + maxx) / 2.0
midy = (miny + maxy) / 2.0
and you can use the following for any rotation:
Code:
if (x >= minx && maxx <= maxx && y >= miny && y <= maxy) {
    dx = x - midx
    dy = y - midy
    x = midx + dx * cosr + dy * sinr
    y = midy - dx * sinr + dy * cosr
}
Since the result has to have integral coordinates, use
Code:
printf("%s%.0f,%.0f;",cmd,x,y);
or (to get unsigned zeroes) convert the results to integers via
Code:
if (x >  0) x = int(x + 0.5)
if (x <  0) x = int(x - 0.5)
if (x == 0) x = 0
if (y >  0) y = int(y + 0.5)
if (y <  0) y = int(y - 0.5)
if (y == 0) y = 0
since in awk int(-0.7) == -0

The complete awk script:
Code:
BEGIN {
    RS="[;\n\r]";
    FS="[, \t]+";
    rotation = rotation % 360.0
    radians = rotation * 3.14159265358979323846 / 180.0
    sinr = sin(radians)
    cosr = cos(radians)
    midx = (minx + maxx) / 2.0
    midy = (miny + maxy) / 2.0
}

/[[:space:]]*(PU|PD)[-[:digit:]]+/ {
    cmd = substr($1,1,2);

    dx = substr($1,3) - midx;
    dy = $2 - midy;

    x = midx + dx * cosr + dy * sinr
    y = midy - dx * sinr + dy * cosr

    if (x >  0) x = int(x + 0.5)
    if (x <  0) x = int(x - 0.5)
    if (x == 0) x = 0
    if (y >  0) y = int(y + 0.5)
    if (y <  0) y = int(y - 0.5)
    if (y == 0) y = 0

    printf("%s%d,%d;", cmd, x, y)
    next
}

/[^;[:space:]]/ { printf("%s;", $0) }
Does this help?
Nominal Animal

Last edited by Nominal Animal; 03-21-2011 at 05:58 AM.
 
Old 01-23-2011, 06:26 AM   #3
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,008

Rep: Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193
ummm ... huh?

I must be a bit off here as I cannot quite work out what it is you are asking to do?
You are printing the newx and newy but I am not seeing what this has to do with 90, 180, 270 degrees?

btw. the following 2 are equivalent:
Code:
{
    if( $1 != "" ) {
	printf("%s;\n", $0);
    }
}

$1
 
Old 01-23-2011, 07:01 AM   #4
gary_in_springhill
Member
 
Registered: Mar 2008
Posts: 136

Original Poster
Rep: Reputation: 21
Unbelievable...

I embarrassed to say 2 days, a headache, and many pots of coffee and you people solved it in 60 min! At least I tried it on my own

Only thing is how do I pass the degree argument coming into bash from python on to awk?


Code:
#!/bin/sh
if [ $1 -eq 90 ]; then
(gawk -f $HOME/bin/minmax.awk $HOME/hpgl-hot-folder/temp.plot  > $HOME/hpgl-hot-folder/temp-conv)
cp $HOME/hpgl-hot-folder/temp.plot $HOME/hpgl-hot-folder/temp2.plot
rm temp.plot
(echo "BEGIN { "; gawk -f $HOME/bin/minmax.awk $HOME/hpgl-hot-folder/temp2.plot; echo "}"; cat $HOME/bin/conv90.awk) > $HOME/bin/temp-conv
gawk -f $HOME/bin/temp-conv $HOME/hpgl-hot-folder/temp2.plot > $HOME/hpgl-hot-folder/temp.plot
fi
 
Old 01-23-2011, 07:58 AM   #5
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,008

Rep: Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193Reputation: 3193
Well I am not sure I see any python in the snippet you have shown, but generally just assign it to a variable using -v and you should be good to go.
 
Old 01-23-2011, 08:20 AM   #6
gary_in_springhill
Member
 
Registered: Mar 2008
Posts: 136

Original Poster
Rep: Reputation: 21
variable from bash

The variable is going to come from bash not python , python originally generates it and passes it to the bash script above. Also that awk script is already being passed two variables $1 $2 so I need "rotation passed along from bash as $3?? It must be a placement somewhere on the awk line that calls the awk script?
 
Old 01-23-2011, 08:36 AM   #7
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
Quote:
Originally Posted by gary_in_springhill View Post
At least I tried it on my own
Right on! That was also why I responded.

Quote:
Originally Posted by gary_in_springhill View Post
Only thing is how do I pass the degree argument coming into bash from python on to awk?
Add option -v rotation=somevalue to the gawk command.
_ _ _ _

You can simplify your script quite a bit, by embedding the two gawk scripts in a single Bash script file.
This will take the rotation angle as the first parameter, then the name or names of the files to be rotated:
Code:
#!/bin/bash
if [ $# -lt 1 ] || [ "$1" == "-h" ] || [ "$1" == "--help" ]; then
    echo "Usage: $0 angle HPGL-file(s)..." >&2
    exit 1
fi

# Take the rotation angle.
angle="$1"
shift 1

# Create a safe temporary directory; also remove it automagically.
temps="/tmp/rotation.`hostname -s`.$$"
trap 'rm -rf "$temps"' EXIT
mkdir -m 0700 "$temps" || exit $?

# File loop.
while [ $# -gt 0 ]; do
    file="$1"
    shift 1
    if [ ! -f "$file" ]; then
        echo "$file: No such file." >&2
        continue
    fi

    # Determine box size: minx miny maxx maxy
    box=(`gawk '
        BEGIN {
            minx = miny = +1e9999
            maxx = maxy = -1e9999
        }

        { /* Compare, e.g. */

            if ($1 < minx) minx = $1
            if ($1 > maxx) maxx = $1

            if ($2 < miny) miny = $2
            if ($2 > maxy) maxy = $2
        }

        END {
            if (minx <= maxx && miny <= maxy)
                print minx, miny, maxx, maxy
        }
    ' "$file" 2>/dev/null`)

    if [ ${#box[@]} -ne 4 ]; then
        echo "$file: Cannot parse box." >&2
        continue
    fi

    if ! gawk -v minx=${box[0]} -v miny=${box[1]} -v maxx=${box[1]} -v maxy=${box[2]} -v rotation=$angle '

        BEGIN {
            RS="[;\n\r]";
            FS="[, \t]+";
            rotation = rotation % 360.0
            radians = rotation * 3.14159265358979323846 / 180.0
            sinr = sin(radians)
            cosr = cos(radians)
            midx = (minx + maxx) / 2.0
            midy = (miny + maxy) / 2.0
        }

        /[[:space:]]*(PU|PD)[-[:digit:]]+/ {
            cmd = substr($1,1,2);

            dx = substr($1,3) - midx;
            dy = $2 - midy;

            x = midx + dx * cosr + dy * sinr
            y = midy - dx * sinr + dy * cosr

            if (x > 0) x = int(x + 0.5)
            if (x < 0) x = int(x - 0.5)
            if (x == 0) x = 0
            if (y > 0) y = int(y + 0.5)
            if (y < 0) y = int(y - 0.5)
            if (y == 0) y = 0

            printf("%s%d,%d;", cmd, x, y)
            next
        }

        /[^;[:space:]]/ { printf("%s;", $0) }

    ' "$file" > "$temps/output" ; then
        rm -f "$temps/output"
        echo "$file: Rotation failed miserably!" >&2
        continue
    fi

    mv -f "$temps/output" "$file"
    echo "$file: Rotated $angle degrees clockwise." >&2
done
The above script could use a nice cleanup. I didn't even test it, but it should be a good starting point.
For one, you'll need to parse the coordinates properly in the first gawk script, similar to the second script.
I find it easier to maintain if each script is in a single file.
Nominal Animal

Last edited by Nominal Animal; 03-21-2011 at 05:56 AM.
 
Old 01-23-2011, 10:14 AM   #8
gary_in_springhill
Member
 
Registered: Mar 2008
Posts: 136

Original Poster
Rep: Reputation: 21
file = ?

In the above file should file="$1" be $2??
I'm having trouble parsing the file location to your script keeps coming back with "usage error" relevant python string is

Code:
job = os.path.expanduser("~/hpgl-hot-folder/temp.plot") 
job = str(job) ##just in case
subprocess.Popen([os.getenv("HOME")+"/bin/rotate2.sh", angle, 'job'], shell=True,stdout=subprocess.PIPE)
When manually runing your script with file=$1 it errors with /home/store/hpgl-hot-folder/temp.plot: Cannot parse box.

If file=$2 the : No such file.
 
Old 01-23-2011, 10:38 AM   #9
gary_in_springhill
Member
 
Registered: Mar 2008
Posts: 136

Original Poster
Rep: Reputation: 21
on the original multi file setup?

I'm not sure but I think I have the variable passing in the wrong spot??
Code:
(gawk -f $HOME/bin/minmax.awk $HOME/hpgl-hot-folder/temp.plot  > $HOME/hpgl-hot-folder/temp-conv)
cp $HOME/hpgl-hot-folder/temp.plot $HOME/hpgl-hot-folder/temp2.plot
rm $HOME/hpgl-hot-folder/temp.plot
(echo "BEGIN { "; gawk -v rotation=90  -f $HOME/bin/minmax.awk $HOME/hpgl-hot-folder/temp2.plot; echo "}"; cat $HOME/bin/rotate.awk) > $HOME/bin/temp-conv
gawk -f $HOME/bin/temp-conv $HOME/hpgl-hot-folder/temp2.plot > $HOME/hpgl-hot-folder/temp.plot
-v rotation=90 looks like it should go here??
 
Old 01-23-2011, 12:11 PM   #10
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
Quote:
Originally Posted by gary_in_springhill View Post
When manually runing your script with file=$1 it errors with /home/store/hpgl-hot-folder/temp.plot: Cannot parse box.
That's to be expected, since I didn't include the coordinate scanning part (your minmax.awk). I hoped you'd read the code and notice and fix it yourself. There were other issues, like only supporting PU and PD and only with one point, too.

$1 is correct, since shift 1 pops the first parameter ($1) off, and shifts the rest of the parameters one place down. $# is always the number of parameters left.

To save us time, here's a bit more complete version (still untested, though):
Code:
#!/bin/bash
if [ $# -lt 1 ] || [ "$1" == "-h" ] || [ "$1" == "--help" ]; then
    echo "Usage: $0 angle HPGL-file(s)..." >&2
    exit 1
fi

# Take the rotation angle.
angle="$1"
shift 1

# Create a safe temporary directory; also remove it automagically.
temps="/tmp/rotation.`hostname -s`.$$"
trap 'rm -rf "$temps"' EXIT
mkdir -m 0700 "$temps" || exit $?

# File loop.
while [ $# -gt 0 ]; do
    file="$1"
    shift 1
    if [ ! -f "$file" ]; then
        echo "$file: No such file." >&2
        continue
    fi

    # Determine box size: minx miny maxx maxy
    box=(`gawk '

        BEGIN {
            minx = miny = +1e9999
            maxx = maxy = -1e9999
            RS="[;\n\r]+";
            FS="[, \t]+";
        }

        ($1 ~ /^[Pp][UuDd]/) {
            $1 = substr($1, 2);
            for (i = 1; i < NF; i += 2) {
                j = i + 1
                x = int($i)
                y = int($j)
                if (x < minx) minx = x
                if (x > maxx) maxx = x
                if (y < miny) miny = y
                if (y > maxy) maxy = y
            }
        }

        END {
            if (minx <= maxx && miny <= maxy)
                print minx, miny, maxx, maxy
        }' "$file" 2>/dev/null`)

    if [ ${#box[@]} -ne 4 ]; then
        echo "$file: Cannot parse box." >&2
        continue
    fi

    if ! gawk -v minx=${box[0]} -v miny=${box[1]} -v maxx=${box[1]} -v maxy=${box[2]} -v rotation=$angle '

        BEGIN {
            RS="[;\n\r]+";
            FS="[, \t]+";
            rotation = rotation % 360.0
            radians = rotation * 3.14159265358979323846 / 180.0
            sinr = sin(radians)
            cosr = cos(radians)
            midx = (minx + maxx) / 2.0
            midy = (miny + maxy) / 2.0
        }

        ($1 ~ /^[Pp][UuDd]/) {
            s = substr($1, 1, 2)
            $1 = substr($1, 3)

            for (i = 1; i < NF; i += 2) {
                j = i+1
                dx = $i - midx
                dy = $j - midy
                x = midx + dx * cosr + dy * sinr
                y = midy - dx * sinr + dy * cosr
                if (x > 0) x = int(x + 0.5)
                if (x < 0) x = int(x - 0.5)
                if (x == 0) x = 0
                if (y > 0) y = int(y + 0.5)
                if (y < 0) y = int(y - 0.5)
                if (y == 0) y = 0
                printf("%s%d,%d", s, x, y)
                s = ","
            }
            printf(";")
            next
        }

        /[^\t ]/ { printf("%s;", $0) }

        ' "$file" > "$temps/output" ; then
        rm -f "$temps/output"
        echo "$file: Rotation failed miserably!" >&2
        continue
    fi

    mv -f "$temps/output" "$file"
    echo "$file: Rotated $angle degrees clockwise." >&2
done
Nominal Animal

Last edited by Nominal Animal; 03-21-2011 at 07:39 AM.
 
1 members found this post helpful.
Old 01-23-2011, 12:52 PM   #11
gary_in_springhill
Member
 
Registered: Mar 2008
Posts: 136

Original Poster
Rep: Reputation: 21
thanks nominal

I've got it going just now with the multi file script and the correct variable input but I'll work on the more efficient one on one of those sleepless nights I have .....

As always thanks so much for your help
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
C (math.h)not doing right math? exp() issue. knockout_artist Programming 7 11-25-2011 02:13 PM
LXer: Simple Cumulative Math Using Awk On Unix or Linux LXer Syndicated Linux News 0 06-30-2008 01:20 AM
math program that I can enter math functions ... Four General 5 04-19-2006 08:02 PM
how can I invoke "awk" from shell to do floating point math? Joseph Schiller Programming 8 01-12-2006 05:00 AM
how to pivot a LCL in Lunix Veteq Linux - General 0 01-29-2005 07:19 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 09:30 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration