Commit 5fe4aa7e authored by Paffenholz, Andreas's avatar Paffenholz, Andreas

programs ch 15, Graham Scan

parent 9bb3d3ae
/*************************************
* Beispielprogramm zur Vorlesung
* Einfuehrung in die Programmierung I
* Andreas Paffenholz
* TU Darmstadt, Wintersemester 2020/21
* (c) 2020-
*
* Graham Scan
**************************************/
#ifdef __linux__
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include "graham_scan.h"
int ccw(struct point* p1, struct point* p2, struct point* p3) {
int turn = (p2->x - p1->x)*(p3->y - p1->y) - (p2->y - p1->y)*(p3->x - p1->x);
return turn;
}
int find_min(struct pointSet* pointset) {
struct point* point = pointset->points;
struct point* tmp = pointset->points;
int index = 0;
for(int i = 0; i < pointset->n_points; i++) {
if( point->y < tmp->y ) {
tmp = point;
index = i;
} else if( point->y == tmp->y ) {
if( point->x < tmp->x ) {
tmp = point;
index = i;
}
}
point++;
}
return index;
}
void graham_scan(struct pointSet* pointset, int* verts, int* n_verts) {
if ( pointset->n_points == 0 ) {
*n_verts = 0;
verts[0] = 0;
return;
}
if ( pointset->n_points == 1 ) {
*n_verts = 1;
verts[0] = 0;
return;
}
int index = find_min(pointset);
swap(pointset, 0, index);
angles(pointset);
struct point* start = (struct point*)malloc(sizeof(struct point));
start->x = (pointset->points[0]).x;
start->y = (pointset->points[0]).y;
#ifdef __APPLE__
qsort_r(pointset->points, (size_t)pointset->n_points, sizeof(struct point), (void *)start, &compare);
#else
qsort_r(pointset->points, (size_t)pointset->n_points, sizeof(struct point), &compare, (void *)start);
#endif
free(start);
verts[0] = 0;
verts[1] = 1;
int head = 1;
for(int i = 2; i <= pointset->n_points; i++){
while(head >= 1 &&
ccw(pointset->points+verts[head-1],
pointset->points+verts[head],
pointset->points+(i % pointset->n_points)) <= 0 ) {
head--;
}
if ( i != pointset->n_points )
verts[head+1] = i;
head++;
}
if ( head == 1 ) {
if ( pointset->points->x != (pointset->points+verts[1])->x || pointset->points->y != (pointset->points+verts[1])->y )
head++;
}
*n_verts = head;
}
/*************************************
* Beispielprogramm zur Vorlesung
* Einfuehrung in die Programmierung I
* Andreas Paffenholz
* TU Darmstadt, Wintersemester 2020/21
* (c) 2020-
*
* Graham Scan, Header
**************************************/
#ifndef GRAHAM_SCAN_H
#define GRAHAM_SCAN_H
#include "point_set.h"
void graham_scan(struct pointSet*, int*, int*);
#endif
\ No newline at end of file
/*************************************
* Beispielprogramm zur Vorlesung
* Einfuehrung in die Programmierung I
* Andreas Paffenholz
* TU Darmstadt, Wintersemester 2020/21
* (c) 2020-
*
* Kürzeste Wege in Netzwerken, Testprogramm
*
* Uebersetzen mit
* gcc graham_scan_main.c graham_scan.c point_set.c -o graham_scan
* Aufruf mit
* ./graham_scan ps01.dat ch.dat
**************************************/
#ifdef __linux__
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <stdlib.h>
#include "graham_scan.h"
#include "point_set.h"
int main(int argc, char** argv){
if(argc != 3){
printf("./%s Eingabedateil Ausgabedatei\n", argv[0]);
return 1;
}
char* input = argv[1];
char* output = argv[2];
struct pointSet* points = read_input(input);
int * verts = (int *)malloc(points->n_points*sizeof(int));
int n_verts = 0;
graham_scan(points, verts, &n_verts);
store_verts(points, verts, n_verts, output);
free_pointset(points);
free(verts);
return 0;
}
/*************************************
* Beispielprogramm zur Vorlesung
* Einfuehrung in die Programmierung I
* Andreas Paffenholz
* TU Darmstadt, Wintersemester 2020/21
* (c) 2020-
*
* Punktmengen
**************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "point_set.h"
#ifdef __APPLE__
int compare(void* c, const void* a, const void* b) {
#else
int compare(const void* a, const void* b, void* c) {
#endif
const struct point* p1 = (const struct point*)a;
const struct point* p2 = (const struct point*)b;
// Die Winkel sind als rationale Zahlen gegeben
// Wir multiplizieren aus fuer den Vergleich
int c1 = p1->angle_num*p2->angle_denom;
int c2 = p2->angle_num*p1->angle_denom;
if ( c1 == c2 ) {
// Die Winkel sind gleich
// Wir vergleichen zuerst die Differenz in x-Richtung
const struct point* start = (const struct point*)c;
int xdiff1 = p1->x - start->x;
int xdiff2 = p2->x - start->x;
if ( xdiff1 != xdiff2 ) {
return ( xdiff1 > xdiff2 ) - ( xdiff2 > xdiff1 );
} else {
// wenn die x-Richtung übereinstimmt, dann liegen die Punkte
// senkrecht ueber start, wir vergleichen y-Koordinaten
int ydiff1 = p1->y - start->y;
int ydiff2 = p2->y - start->y;
return ( ydiff1 > ydiff2 ) - ( ydiff2 > ydiff1 );
}
}
return (c1 > c2) - (c2 > c1);
}
void swap(struct pointSet* pointset, int i1, int i2) {
struct point tmp = pointset->points[i1];
pointset->points[i1] = pointset->points[i2];
pointset->points[i2] = tmp;
}
void angle(struct point* p1, struct point* p2, int* num, int* denom) {
int dot = p2->x-p1->x;
*num = (dot<0?-1:1)*dot*dot;
*denom = (p2->x-p1->x)*(p2->x-p1->x) + (p2->y-p1->y)*(p2->y-p1->y);
if ( *num == 0 && *denom == 0 ) {
*num = -1;
*denom = -1;
}
}
void angles(struct pointSet* pointset) {
int num, denom;
(pointset->points[0]).angle_num = -1;
(pointset->points[0]).angle_denom = 1;
struct point* l = pointset->points;
for(int i = 1; i< pointset->n_points; i++){
struct point* p = pointset->points+i;
angle(p,l,&num,&denom);
p->angle_num = num;
p->angle_denom = denom;
}
}
struct pointSet* read_input(char* filename) {
FILE *infile;
infile = fopen (filename, "r");
if (infile == NULL) {
fprintf(stderr, "\nError opening file\n");
exit (1);
}
struct pointSet* points = (struct pointSet*)malloc(sizeof(struct pointSet));
const char s[2] = " ";
char * line = NULL;
size_t len = 0;
size_t read;
char *next;
read = getline(&line, &len, infile);
points->n_points = atoi(line);
points->points = malloc(points->n_points*sizeof(struct point));
int i = 0;
struct point* point = points->points;
while ((read = getline(&line, &len, infile)) != -1) {
next = strtok(line, s);
if ( !next || strcmp(next,"\n")==0 ) {
continue;
}
point->x = atoi(next);
next = strtok(NULL, s);
point->y = atoi(next);
point++;
i++;
}
if( line ) {
free(line);
}
fclose(infile);
return points;
}
void print_point(struct point* point, int index, int show_angle ) {
if ( show_angle ) {
printf("%d: (%d %d) -- angle %f\n", index, point->x, point->y, (float)(point->angle_num)/point->angle_denom);
} else {
printf("%d: (%d %d)\n", index, point->x, point->y);
}
}
void print_points(struct pointSet* pointset, int show_angle ) {
printf("---------------------------------\nPoint set with %d points\n", pointset->n_points);
struct point* point = pointset->points;
for(int i = 0; i < pointset->n_points; i++){
print_point(point, i, show_angle);
point++;
}
printf("---------------------------------\n");
}
void store_verts(struct pointSet* pointset, int* verts, int n_verts, char* filename) {
FILE* file = fopen(filename, "w");
fprintf(file, "%d\n", n_verts);
for(int i = 0; i < n_verts; i++) {
struct point* point = pointset->points+verts[i];
fprintf(file, "%d %d\n", point->x, point->y);
}
fclose(file);
}
void free_point(struct point* point) {
free(point);
}
void free_pointset(struct pointSet* pointset) {
free(pointset->points);
free(pointset);
}
/*************************************
* Beispielprogramm zur Vorlesung
* Einfuehrung in die Programmierung I
* Andreas Paffenholz
* TU Darmstadt, Wintersemester 2020/21
* (c) 2020-
*
* Punktmengen, Header
**************************************/
#ifndef POINT_SET_H
#define POINT_SET_H
struct point {
int x;
int y;
int angle_num;
int angle_denom;
};
struct pointSet {
int n_points;
struct point* points;
};
#ifdef __APPLE__
int compare(void*, const void*, const void*);
#else
int compare(const void*, const void*, void*);
#endif
struct pointSet* read_input(char*);
void store_verts(struct pointSet*, int*, int, char*);
void swap(struct pointSet* , int, int);
void angles(struct pointSet* );
void print_points(struct pointSet*,int);
void free_pointset(struct pointSet*);
#endif
\ No newline at end of file
11
0 2
4 2
4 4
6 0
6 4
8 6
10 2
10 4
10 6
12 2
12 4
\ No newline at end of file
13
0 2
4 0
4 2
4 4
6 0
6 4
8 0
8 2
8 6
10 2
10 4
10 6
12 4
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment