Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
delaunay.c 7.11 KiB
/*
 ============================================================================
 Name        : constant-workspace-algorithms-c.c
 Author      : Mika Delor
 Version     :
 Copyright   : Your copyright notice
 Description : Hello World in C, Ansi-style
 ============================================================================
 */

#include "delaunay.h"







int comparePointsByX (const void * a, const void * b) {
   vertex* pointA = (vertex*) a;
   vertex* pointB = (vertex*) b;
   if(pointA->x > pointB->x)
	   return 1;
   if(pointA->x < pointB->x)
	   return -1;
   return 0;
}




/*int reportLine(vertex* p, int size, FILE *out) {
	line l = {p[0], p[1]};
	svgDrawLine(l, out);
	l.a = p[0];
	l.b = p[2];
	svgDrawLine(l, out);
	return 1;
}*/

void reportTriangle(vertex a, vertex b, vertex c) {

//	qsort (p, size, sizeof(*p), comparePointsByX);
//
//	char *color = "255,0,0";
#ifdef OUTPUTFILE
	svgDrawTriangle(a, b, c);
#endif

//	edge l = {p[0], p[1]};
//	svgDrawLine(l, out, color);
//	l.b = p[2];
//	svgDrawLine(l, out, color);
//	l.a = p[1];
//	svgDrawLine(l, out, color);

}






//http://mathforum.org/library/drmath/view/54323.html
circle circle_vvv(vertex v1, vertex v2, vertex v3)
{
	circle c;
    double bx = v1.x; double by = v1.y;
    double cx = v2.x; double cy = v2.y;
    double dx = v3.x; double dy = v3.y;
    double temp = cx*cx+cy*cy;
    double bc = (bx*bx + by*by - temp)/2.0;
    double cd = (temp - dx*dx - dy*dy)/2.0;
    double det = (bx-cx)*(cy-dy)-(cx-dx)*(by-cy);
    if (fabs(det) < 1.0e-6) {
        c.center.x = c.center.y = 1.0;
        return c;
        }
    det = 1/det;
    c.center.x = (bc*(cy-dy)-cd*(by-cy))*det;
    c.center.y = ((bx-cx)*cd-(cx-dx)*bc)*det;
    cx = c.center.x; cy = c.center.y;
    c.radius = distance(v1, c.center);
    return c;
}


double det2(double a, double b, double c, double d) {
	return a*d-b*c;
}

void circleCenter(const vertex* v1, const vertex* v2, const vertex* v3,
		vertex* center) {
	double ax = 2 * (v1->x - v2->x);
	double bx = 2 * (v1->y - v2->y);
	double cx = v1->x * v1->x - v2->x * v2->x + v1->y * v1->y - v2->y * v2->y;
	double ay = 2 * (v1->x - v3->x);
	double by = 2 * (v1->y - v3->y);
	double cy = v1->x * v1->x - v3->x * v3->x + v1->y * v1->y - v3->y * v3->y;
	double det = det2(ax, bx, ay, by);
	center->x = det2(cx, bx, cy, by) / det;
	center->y = det2(ax, cx, ay, cy) / det;
}

/*
 * https://stackoverflow.com/questions/22791951/algorithm-to-find-an-arc-its-center-radius-and-angles-given-3-points
 * https://de.wikipedia.org/wiki/Cramersche_Regel
 * https://de.wikipedia.org/wiki/Determinante
 */
//TODO seperate radius from this function
circle circleFrom3Points(vertex v1, vertex v2, vertex v3) {
	circle c;
	circleCenter(&v1, &v2, &v3, &c.center);
	c.radius = sqrt((v1.x-c.center.x)*(v1.x-c.center.x)+(v1.y-c.center.y)*(v1.y-c.center.y));
	return c;
}

/*void reportTriangle(struct Triangle triangle) {
	printf("%f, %f - %f, %f - %f, %f\n", triangle.a.x, triangle.a.y, triangle.b.x, triangle.b.y, triangle.c.x, triangle.c.y);
}*/
void printPoint(vertex point) {
	//printf("%f, %f\n", point.x, point.y);
}





double calcArea(vertex p, vertex q, vertex r) {
	//return 0.5*(-q.x*p.y+r.x*p.y+p.x*q.y-r.x*q.y-p.x*r.y+q.x*r.y);
	return 0.5*(p.x*(q.y-r.y)-p.y*(q.x-r.x)+(q.x*r.y-q.y*r.x));
}

/**
 *
 * @param p1
 * @param p2
 * @return the distance between p1 and p2
 */
double distance(vertex p1, vertex p2) {
	return hypot(p1.x - p2.x, p1.y-p2.y);
}

//https://math.stackexchange.com/questions/1232773/is-the-point-on-the-left-or-the-right-of-the-vector-in-2d-space
//https://betterexplained.com/articles/cross-product/
/**
 *
 * @param p
 * @param q
 * @param r
 * @return true, if r lies right of the vector pointing from p to q, false otherwise
 */
int isRight(vertex p, vertex q, vertex r) {
	vertex a;
	vertex b;
	a = vector(p, q);
	b = vector(p, r);
	return a.x*b.y-a.y*b.x > 0;
}

/**
 *
 * @param a Point
 * @param b Point
 * @return the vector pointing from a to b
 */
vertex vector(vertex a, vertex b) {
	double x = a.x - b.x;
	double y = a.y - b.y;
	vertex p = {x, y};
	return p;
}

/**
 * law of cosines https://www.mathsisfun.com/algebra/trig-cosine-law.html
 * other solutions https://stackoverflow.com/questions/1211212/how-to-calculate-an-angle-from-three-points
 * @param q
 * @param p
 * @param r
 * @return angle qpr (angle in p)
 */
double calcAngle(vertex q, vertex p, vertex r) {
	double pq = distance(p, q);
	double pr = distance(p, r);
	double qr = distance(q, r);
	return acos((pq*pq + pr*pr - qr*qr)/(2*pq*pr));
}

int firstDelaunayEdgeIncidentTo(int j, vertex* S, int size) {
	int k;
	double minDist, dist;
	if(j != 0) {
		k = 0;
		minDist = distance(S[j], S[0]);
	} else /*if(j != 1)*/ {
		k = 1;
		minDist = distance(S[j], S[1]);
	}
	//TODO erst bei j anfangen? problem: es ist nicht unbedingt die kleinste seite, wenn wir spaeter anfangen
	for(int i = 0; i < size; i++) {
		if(j != i) {
			dist = distance(S[j], S[i]);
			if(dist < minDist) {
				k = i;
				minDist = dist;
			}
		}
	}
	return k;
}

int arrayContains(int *jAlreadyUsed, int numberOfJ, int j){
	for(int i = 0; i < numberOfJ; i++) {
		if(jAlreadyUsed[i] == j) {
			return 1;
		}
	}
	return 0;
}

void clockwiseNextDelaunayEdge(const int *p, const int *q, int *r, const vertex *S, const int *size, int *right) {
	//0: r not initialized, 1: r is left, 2: r is right
	*right = 0;
	double maxAngle;
	circle c;
	//area and angle into 1 var
	double angle;
	for(int i = 0; i < *size; i++) {
		if(i == *p || i == *q) {

		} else if(isRight(S[*p], S[*q], S[i])) {
			//maximize signed area
			//http://mathworld.wolfram.com/TriangleArea.html
			if(*right < 2) {
				//calc circle
				*right = 2;
				*r = i;
				c = circleFrom3Points(S[*p], S[*q], S[*r]);
			} else {
				//if inside circle: calculate new circle, else: do nothing
				if(distance(c.center, S[i]) < c.radius) {
					*r = i;
					c = circleFrom3Points(S[*p], S[*q], S[*r]);
				}
			}
		} else if(*right < 2) {
			//maximize angle qpr
			angle = calcAngle(S[*q], S[*p], S[i]);
			//TODO is c 'or' lazy, if yes combine if and if else
			//TODO only return edge and not entire triangle, if left
			if(*right < 1) {
				*right = 1;
				maxAngle = angle;
				*r = i;
			} else if(angle > maxAngle){
				maxAngle = angle;
				*r = i;
			}
		}
	}

	//if you want to draw the circle comment this line out
	//svgDrawCircle(c, out);
}



void delaunayCws(vertex* S, int size) {
	//struct Triangle delaunayTriangles[size-2];
	for(int i = 0; i < size; i++){
		//TODO eventuell nur j zurueckgeben (i haben wir ja schon)
		int j = firstDelaunayEdgeIncidentTo(i, S, size);
		// Find the point p[j] e S that is nearest to p[i]
		int j0 = j;
		do {
			//TODO eventuell nur k zurueckgeben (i haben wir ja schon)
			int k;
			int isTriangle;
			clockwiseNextDelaunayEdge(&i, &j, &k, S, &size, &isTriangle);
			if(i < j && i < k) {
				if(isTriangle == 2){
#ifdef OUTPUTFILE
					reportTriangle(S[i], S[j], S[k]);
#endif
				}
			}
			j = k;
		} while(j != j0);
	}
}

//https://stackoverflow.com/questions/29762048/c-structure-to-string
char* vertexToString(vertex v) {
	int len = 0;
	len = snprintf(NULL, len, "%f,%f", v.x, v.y);
	char* str = malloc(sizeof(char) * len + 1);
	snprintf(str, sizeof(str), "%f,%f", v.x, v.y);
	return str;
}