简单三角形,三角剖分切耳法C实现,链表操作序号,剔除共线点。 供参考。
复杂三角形未另加处理,自行修改。
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "geom.h"
#define EPS 1e-4
#define ABS(a) ((a) > 0 ? (a) : (-a))
typedef struct _IndiceNode {
int i;
struct _IndiceNode* prev;
struct _IndiceNode* next;
} IndiceNode;
static IndiceNode* addNode(IndiceNode* idn, int i)
{
if (idn == NULL) {
idn = (IndiceNode*) malloc(sizeof(IndiceNode));
if(!idn) return NULL;
idn->prev = idn;
idn->next = idn;
idn->i = i;
return idn;
} else {
IndiceNode* n = (IndiceNode*) malloc(sizeof(IndiceNode));
if(!n) return NULL;
n->i = i;
n->prev = idn;
n->next = idn->next;
idn->next->prev = n;
idn->next = n;
return n;
}
}
static IndiceNode* delNode(IndiceNode* idn)
{
if (idn->next != idn) {
IndiceNode* next = idn->next;
idn->prev->next = idn->next;
idn->next->prev = idn->prev;
free(idn);
return next;
} else {
free(idn);
return NULL;
}
}
static void freeNodes(IndiceNode* idn)
{
while(idn != NULL)
idn = delNode(idn);
}
static inline float cross(float* A, float* B, float* C, float* D)
{
return (B[0] - A[0]) * (D[1] - C[1]) - (B[1] - A[1]) * (D[0] - C[0]);
}
static bool inside(float* A, float* B, float* C, float* P)
{ // point outside triangle , one angle > 180
float PAPB = cross(P,A,P,B);
float PBPC = cross(P,B,P,C);
float PCPA = cross(P,C,P,A);
return PAPB*PBPC >= 0 && PBPC*PCPA >= 0;
}
static float area(float* pt, IndiceNode* idn)
{
float* p = &pt[idn->prev->i*2];
float* c = &pt[idn->i*2];
float* n = &pt[idn->next->i*2];
return cross(p,c,c,n);
}
static float areasum(float* pt, IndiceNode* idn)
{
float sum = 0;
IndiceNode* head = idn;
do {
float* c = &pt[idn->i*2];
float* n = &pt[idn->next->i*2];
sum += c[0]*n[1] - c[1]*n[0];
idn = idn->next;
} while (idn != head);
return sum;
}
int triangulate(float* points, int num, int** pindices)
{
if (num < 3)
return 0;
int indiceSize = (num-2)*sizeof(int)*3;
int* indices = (int*) malloc(indiceSize);
memset(indices, 0, indiceSize);
int indicesNum = 0;
IndiceNode* idn = NULL;
int pnum = 0;
for(int i = 0; i < num; i++) // skip same point or extra on line point
{
int next = (i< (num-1))? i+1 : 0;
int prev = (i+num-1)%num;
if( length(points+i*2 , points+ next*2) > EPS &&
dist(points+prev*2,points+next*2,pts+i*2) > EPS))
{
idn = addNode(idn,i);
pnum++;
}
}
idn = idn->next;
int sign;
{
float s = areasum(points, idn);
if (s > 0) sign = 1;
else sign = -1;
}
int changed = 0;
int loopn = 0;
while (pnum >= 3)
{
if(loopn++ > pnum) break;
float* a = points + idn->prev->i * 2;
float* b = points + idn->i * 2;
float* c = points + idn->next->i * 2;
if (changed) {
float* e = points+ idn->prev->prev->i*2;
float dt = dist(e,b,a);
if (dt < EPS) {
delNode(idn->prev);
pnum--;
continue;
} else
changed = 0;
}
float dt = dist(a,c,b);
if (dt < EPS) {
idn = delNode(idn);
pnum--;
continue;
}
float area = crossp(a,b,b,c)*sign;
if (area < 0) {
idn = idn->next;
continue;
}
IndiceNode* tmp = idn->next->next;
while( tmp != idn->prev) {
float* p = points + tmp->i * 2;
if (inside(a,b,c,p))
break;
tmp = tmp->next;
}
if (tmp == idn->prev) {
indices[indicesNum*3] = idn->prev->i;
indices[indicesNum*3+1] = idn->i;
indices[indicesNum*3+2] = idn->next->i;
indicesNum++;
idn = delNode(idn);
pnum--;
changed = 1;
loopn = 0;
} else
idn = idn->next;
}
freeNodes(idn);
if (indicesNum != num - 2)
indices = (int*)realloc(indices,indicesNum*sizeof(int)*3);
*pindices = indices;
return indicesNum;
}
int main()
{
float pt[] = {27.6646309, 268.459106, 82.9805145, 206.147369, 87.5336533, 215.079193, 93.186615, 218.754639, 99.2581711, 217.941269, 105.066978, 213.406494, 109.931747, 205.917786, 113.171219, 196.242584, 114.104065, 185.148346, 112.049011, 173.402542, 117.580589, 167.171371, 126.023453, 174.403473, 133.997955, 177.379547, 140.952484, 176.720947, 146.335358, 173.049133, 149.59494, 166.985474, 150.179596, 159.151413, 147.537659, 150.168365, 141.117508, 140.657715, 196.378067, 78.4082718};
int size = sizeof(pt)/sizeof(pt[0]) / 2;
int* pindices ;
int num = triangulate( pt, size,&pindices);
for(int i = 0; i < num; i++){
int* p = &pindices[i*3];
printf("%d %d %d \n",*p,*(p+1),*(p+2));
}
free(pindices);
}