If you haven't sorted it out yet, your problem is obvious. You read the data for the first polygon and then you calculate the perimeter
:
perimeter += getDistance(a, initialPoint);
printf("First polygon is %d
", poly_id);
printf("perimeter = %2.2lf m
", perimeter);
Then, inexplicably, you read data for your second polygon before calculating the area:
scanf("%d %d", &npoints, &poly_id);
double x[MAX_PTS], y[MAX_PTS];
double area = 0;
<snip>
area = polygon_area(npoints, x, y);
How you expect to get the area for the first polygon using data for the second polygon is a bit bewildering.
What you need to do is calculate both the perimeter
and the area
for each polygon before reading the data for the next. Rather than your if
block of code, you would usually prompt to enter the number of polygons
to process and then do something like:
for (i = 0; i < npolys; i++)
{
<read data for poly>
<calculate perimeter>
<calculate area>
<display results>
}
Next, when you expect data from a user, prompt for it. Don't just leave the user looking at a blinking cursor wondering if your program hung, etc.. A simple printf
asking for the number of points and polygon id works fine. Then a like prompt to enter each x/y pair goes a long way to eliminating confusion. Taking all the above into consideration, your code could be re-written as:
int main (void) {
size_t npoints, poly_id;
size_t npolys = 0;
size_t it = 0;
struct Point a, b;
printf ("
Number of polygons to enter: ");
scanf (" %zu", &npolys);
for (it = 0; it < npolys; it++)
{
double x[MAX_PTS], y[MAX_PTS];
double perimeter = 0;
double area = 0;
size_t iter = 0;
printf ("
Enter npoints & poly_id : ");
scanf("%zu %zu", &npoints, &poly_id);
printf ("Enter the first point X & Y: ");
scanf("%lf %lf", &a.x, &a.y);
x[iter] = a.x;
y[iter] = a.y;
struct Point initialPoint = a;
for (iter = 1; iter < npoints; ++iter)
{
printf (" next point X & Y: ");
scanf("%lf %lf", &b.x, &b.y); /* input for new-point. */
x[iter] = b.x;
y[iter] = b.y;
perimeter += getDistance(a, b); /* add the perimeter. */
a = b; /* new-pt is first-pt */
}
/* complete polygon joining the last-point with initial-point. */
perimeter += getDistance (b, initialPoint);
area = polygon_area (npoints, x, y);
printf("
Polygon %zu is %zu
", it, poly_id);
printf("perimeter = %2.2lf m
", perimeter);
printf(" area = %2.2lf m^2
", area);
}
return 0;
}
But why not write an input routine for your code to read your data file and eliminate the error prone user input? It takes a little time, but it's not hard. That way you can completely separate the input and processing functions of your code.
That frees you to actually concentrate on laying the processing part of your code out in a logical manner, instead of having the processing logic sprinkled with user input. The following is an example of how separating input from the logic of your code can help keep your code clean and readable. It reads all data into an array of structures before beginning the first computation.
When you keep your code separated into logical function, it makes maintaining any individual computation like perimeter
or area
a simple matter of adjusting the logic of a single function. Take a look at the following and let me know if you have questions:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <math.h>
#define MAXPTS 100
#define MAXPOLYS 100
typedef struct point {
double x, y;
} point;
typedef struct polygon {
size_t sz;
size_t id;
point *vertex;
} polygon;
double get_distance (point a, point b);
double poly_perim (polygon a);
double polygon_area (polygon pg);
polygon *read_data (char *fn);
int main (int argc, char **argv)
{
if (argc < 2 ) {
fprintf (stderr, "error: insufficient input, usage: %s filename
", argv[0]);
return 1;
}
size_t it = 0;
size_t idx = 0;
polygon *pg = read_data (argv[1]);
if (!pg) return 1;
while (pg[idx].sz)
{
printf ("
id: %zu points: %zu perimeter: %6.2lf area: %6.2lf
",
pg[idx].id, pg[idx].sz, poly_perim (pg[idx]), polygon_area (pg[idx]));
for (it = 0; it < pg[idx].sz; it++)
printf (" %5.2lf %5.2lf
", pg[idx].vertex[it].x, pg[idx].vertex[it].y);
idx++;
}
return 0;
}
double get_distance (point a, point b)
{
double distance;
distance = sqrt ((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
return distance;
}
double poly_perim (polygon a)
{
int i = 0;
double perim = get_distance (a.vertex[0], a.vertex[a.sz -1]);
for (i = 1; i < a.sz; i++)
perim += get_distance (a.vertex[i-1], a.vertex[i]);
return perim;
}
double polygon_area (polygon pg)
{
double area = 0.0;
int i = 0;
for (i = 0; i < pg.sz; ++i)
{
int j = (i + 1) % pg.sz;
area += (pg.vertex[i].x * pg.vertex[j].y - pg.vertex[j].x * pg.vertex[i].y);
}
area /= 2.0;
area = area > 0 ? area : -1 * area;
return area;
}
polygon *read_data (char *fn)
{
char *ln = NULL;
size_t n = 0;
size_t it = 0;
size_t idx = 0;
ssize_t nchr = 0;
FILE *fp = NULL;
polygon *pg = NULL;
if (!(fp = fopen (fn, "r"))) {
fprintf (stderr, "%s() error: file open failed '%s'.
", __func__, fn);
exit (EXIT_FAILURE);
}
if (!(pg = calloc (MAXPOLYS, sizeof *pg))) {
fprintf (stderr, "%s() error: virtual memory allocation failed.
", __func__);
exit (EXIT_FAILURE);
}
while ((nchr = getline (&ln, &n, fp)) != -1)
{
char *p = ln;
char *ep = NULL;
long lnum = 0;
double dnum = 0;
errno = 0;
lnum = strtol (p, &ep, 10);
if (errno == 0 && (p != ep && lnum != 0))
pg[idx].sz = (size_t)lnum;
else {
fprintf (stderr, "%s() error: file read failure '%s'.
", __func__, fn);
exit (EXIT_FAILURE);
}
p = ep;
errno = 0;
lnum = strtol (p, &ep, 10);
if (errno == 0 && (p != ep && lnum != 0))
pg[idx].id = (size_t)lnum;
else {
fprintf (stderr, "%s() error: file read failure '%s'.
", __func__, fn);
exit (EXIT_FAILURE);
}
pg[idx].vertex = calloc (pg[idx].sz, sizeof *(pg[idx].vertex));
if (!pg[idx].vertex) {
fprintf (stderr, "%s() error: virtual memory allocation failed.
", __func__);
exit (EXIT_FAILURE);
}
for (it = 0; it < pg[idx].sz; it++)
{
p = ep;
errno = 0;
dnum = strtod (p, &ep);
if (errno == 0 && (p != ep && lnum != 0))
pg[idx].vertex[it].x = dnum;
else {
fprintf (stderr, "%s() error: file read failure '%s'.
", __func__, fn);
exit (EXIT_FAILURE);
}
p = ep;
errno = 0;
dnum = strtod (p, &ep);
if (errno == 0 && (p != ep && lnum != 0))
pg[idx].vertex[it].y = dnum;
else {
fprintf (stderr, "%s() error: file read failure '%s'.
", __func__, fn);
exit (EXIT_FAILURE);
}
}
idx++;
if (idx == MAXPOLYS) {
fprintf (stderr, "%s() warning: MAXPOLYS reached in file '%s'.
", __func__, fn);
break;
}
}
fclose (fp);
if (ln) free (ln);
return pg;
}
Input
$ cat dat/poly.txt
3 12867 1.0 2.0 1.0 5.0 4.0 5.0
5 15643 1.0 2.0 4.0 5.0 7.8 3.5 5.0 0.4 1.0 0.4
Output
$ ./bin/poly dat/poly.txt
id: 12867 points: 3 perimeter: 10.24 area: 4.50
1.00 2.00
1.00 5.00
4.00 5.00
id: 15643 points: 5 perimeter: 18.11 area: 19.59
1.00 2.00
4.00 5.00
7.80 3.50
5.00 0.40
1.00 0.40