Last week, we wrote a program to determine if a point was inside the bounding box of a convex polygon. If you remember, we defined a polygon as a list of (x,y) coordinates which represent the verteces of the polygon. You were given the code to read a polygon file, and functions to get information about the polygon.

This week, we will complete the job... determine if the point specified in the program's arguments are actually inside the polygon itself. To illustrate this question, consider the following figure, which shows a triange and a point that is inside the bounding box of that triangle, but is not inside the perimeter of the triangle itself.

The question is, how do we tell the computer how to figure out if the point is inside the perimeter or not?

There are different ways to answer this question, but one easy way to think about this problem is to think of a vertical line that goes through the point in question, like the red line in the following figure.

Notice that the red line intersects exactly two line segments that make up the perimeter of the polygon. If we can determine the (x,y) coordinates of the intersection of this line with the perimeter, that will give us the (x,y) coordinates of the two orange/brown dots in the figure above; namely (1,0) and (1,3.6). Then we can check whether our point, (1,3.9) has a y coordinate between 0 and 3.6. If it does, the point is inside the polygon. If not, the point is outside the polygon. In this case, 3.9 is greater than the higher itersection coordinate of 3.6, so the point is in fact, outside of the triangle.

It turns out that since we are dealing with convex polygons, we can draw a vertical line from a point inside the bounding box of the polygon, and be guaranteed that our line crosses either a segment of the polygon boundary or a vertex of the polygon exactly two times - one low and one high.

We can enumerate the line segments of a polygon if we know its verteces by simply taking two adjaced pairs of vertexes. (Note that the last one is also paired with the first one.) Therefore, if we have verteces from 0 to (n-1), the list of line segments in the perimeter is simply

From | To |
---|---|

vertex 0 | vertex 1 |

vertex 1 | vertex 2 |

... | ... |

vertex n-2 | vertex n-1 |

vertex n-1 | vertex 0 |

It's pretty simple to see if our vertical line crosses a particular segment. Just find the lowest X coordinate of the end-points of the line segment, and if our vertical line X is greater than the lower X, but less than the higher X, then our vertical line crosses that segment.

Once we know that our vertical line crosses a particular segment, we can perform iterpolation to determine the Y coordinate of the intersection of our vertical line with the segment. To do so, we can use the following formula, where the line segment goes from `(x1,y1)` to `(x2,y2)`, and the vertical line is at `xq`

`y_intersect = y1 + (xq-x1) * (y2-y1)/(x2-x1)`

If our vertical line goes through a vertex, then the x coordinate of the vertex must match the x coordinate of the vertical line, and the y coodinate of the intersection is simply the y coordinate of that vertex.

You may either continue using the code you created from last week's lab, or download the Professor's solution to last week's lab as a starting point. (If you didn't finish last week's lab, you may want to just download.) If you want to download the Professor's solution, grab lab5.tar.gz and move it into you home directory. Use the command `tar -xvzf lab5.tar.gz`. This will unpack the tar file and make a new `lab5` subdirectory.

The polygon functions are the same as last week, but I've included the documentation here for reference.

The two C files called `poly.h` and `poly.c` contain the declarations and definitions for the functions to handle polygons. You will not need to change anything in these files, but you do need to understand how to call these functions. Feel free to look at this code, but there are some things in these files, like C structures and typedefs, which we haven't studied yet... so don't worry if you can't understand everything.

The `poly.h` file contains everything you need to invoke the polygon functions. Therefore, we `#include "poly.h"` in our main C file. The function definitions for these files is in the `poly.c` file. But the important thing is how these functions work.

First, we need to talk about the `polygon` data type defined in poly.h. We can declare a variable as a polygon, just like declaring a variable as an integer, by using `polygon p;`. After such a declaration, we can use the variable "p" to hold a polygon. The "makePolygon" function returns a value of the polygon type, so we can do something like `p=makePolygon(x)`. Several other polygon functions require arguments which have a polygon type. We can provide values by using a variable of type polygon, such as: `int n=verteces(p);`.

Now we can describe te functions themselves

`polygon makePolygon(char *fromFile)`- The makePolygon function takes a string which represents the name of a polygon file (in the current directory). The makePolygon function reads the file associated with this name, and returns a polygon value that can then be used in the rest of the polygon functions. If any problems occur, such as the file does not exist, or the file does not contain information about a polygon as expected, then the makePolygon function will write a message (to stderr) and cause the program to exit. In other words, if makePolygon fails, it will never return to the caller, so you don't need to check the return value.`void printPolygon(polygon p)`- This function will print the number of verteces, and the (x,y) coordinates associated with those verteces for polygon p to the standard output stream.`void deletePolygon(polygon p)`- This function will remove all the information associated with polygon p from memory. You should invoke deletePolygon for every polygon created by the makePolygon function.`int verteces(polygon p)`- Returns the number of (x,y) coordinates that make up the verteces of the polygon p.`float vertexX(polygon p,int index)`- Returns the x coordiante value of the index^{th}vertex in polygon p. The value for index should be between 0 and (verteces(p)-1).`float vertexY(polygon p,int index)`- Returns the y coordiante value of the index^{th}vertex in polygon p. The value for index should be between 0 and (verteces(p)-1).

For instance, if I code `polygon p=makePolygon("triangle.txt");`, then when I invoke `printPolygon(p);` then the following will get printed to standard output:

verteces: 3 (0.000000,0.000000) (10.000000,0.000000) (0.000000,4.000000)

Also, the value of `verteces(p)` will be 3; the value of `vertexX(p,1)` will be 10.0; and the value of `vertexY(p,1)` will be 0.0. I should also call `deletePolygon(p);` before I exit.

The Makefile is the same as last week as well...

The `Makefile` file in the lab5 directory contains the recipes to build the C program associated with whose "main" function is in `contains.c`. To build the contains executable, use the `make contains`.

The `Makefile` file contains several other "targets" which allow you to do other things using the make command. The following targets are supported:

`make contains`- Makes the contains executable if you have changed the source code.`make test`- Makes the contains executable if you have changed the source code, and then runs that executable on three test cases.`make clean`- Removes the contains executable.

The file `contains.c` in the lab5 directory contains the code we used last week to read a polygon definition and determine if a point is inside the boundig box of the polygon. You can assume that the first parameter passed into your program (after the name of the program itself) is the name of a polygon definition file, the second parameter is an x coordinate, and the third parameter is a y coordinate. The second and third parameters make up the coordinate of the point you want to check.

Your main function already performs the following actions...

- Checks to make sure three parameters have been specified by your caller. If not, writes an error message and quits.
- Invokes the
`makePolygon`function on the first parameter. - Prints the resulting polygon information.
- Converts the second and third arguments to floating point values.
- Computes the x and y coordinates of the lower left corner of the bounding box and the upper right corner of the bounding box.
- Prints a message that tells the user what the lower left and upper right corners of the bounding box are.
- Checks to see if the (x,y) coordinate specified as the second and third parameters are inside the bounding box of the polygon.
- Prints a message to your caller that specifies the (x,y) coordinate of the user specified point, and tells whether that point is or is not contained in the bounding box of the polygon.

Your job today is to extend the `main` function to determine if a point that is inside the bounding box is also inside the polygon itself. In order to do that, you will need to do the following...

- Loop through the verteces of the polygon, looking for the two places where the vertical red line intersects the boundary of the polygon. In order to find these coordinates, you will have to do the following:
- Check to see if the query X matches this vertex X. If so, the vertex Y coordinate for this vertex is one of the intersection points.
- If not, use this vertex X as the "from" point of a line segment, and figure out what vertex will be the "to" point for the line segment. Then check to see if the query X is between the from and to X's. If not, the red vertical line does not cross this segment. If so, then the red vertical line does cross this segment, and you need to find the y coordinate of the intersection point. Do this by using the interpolation formula described above.

- Once you have the two y coordinates of the intersection of the vertical red line with the boundary of the polygon, you just need to check to see if the query Y coordinate is between the two intersection y coordinates. If so, the point is inside the perimeter of the polygon, and you should print a message to say so. If not, the point is outside the polygon itself, and your message should tell the user the point is outside the polygon.

Here are some hints that will help you write this code...

- Don't even bother to check to see if the point is inside the polygon if the point is outside the bounding box. If the point is outside the bounding box, it CAN'T be inside the polygon.
- Keep the index of the "to" coordinate for a line segment in its own variable, like
`int to_i`Then you can have code like:`if (i==verteces(p)-1) to_i=0; else to_i=i+1;` - Keep track of how many intersections you have found so far. When the number of intersections reaches 2, then you can check to see if the point is inside the polygon or not.
- If you downloaded the Professor's solution, he has already coded a function for you called
`interpolate`which implements the interpolation formula described above.

Good luck and happy coding!

Download and edit the following file: lab5_report.txt. Then submit your editted file on Blackboard in the Lab_05 report area.