切耳法三角剖分C实现

简单三角形,三角剖分切耳法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);
}


  
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yvee

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值