parent
3ca8e64b68
commit
1c305d5ef9
18
src/bmesh.c
18
src/bmesh.c
|
@ -556,7 +556,7 @@ static void addBallToHull(convexHull *hull, bmeshBall *ballForConvexHull,
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "osutil.h"
|
#include "osutil.h"
|
||||||
static int showFaceIndex = 0;
|
int showFaceIndex = 10000000;
|
||||||
static long long lastShowFaceIndexIncTime = 0;
|
static long long lastShowFaceIndexIncTime = 0;
|
||||||
|
|
||||||
static int bmeshStichFrom(bmesh *bm, bmeshBall *parent, bmeshBall *ball) {
|
static int bmeshStichFrom(bmesh *bm, bmeshBall *parent, bmeshBall *ball) {
|
||||||
|
@ -598,7 +598,10 @@ static int bmeshStichFrom(bmesh *bm, bmeshBall *parent, bmeshBall *ball) {
|
||||||
convexHullUnifyNormals(hull, &ball->position);
|
convexHullUnifyNormals(hull, &ball->position);
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
|
|
||||||
if (lastShowFaceIndexIncTime + 300 < osGetMilliseconds()) {
|
/*
|
||||||
|
if (lastShowFaceIndexIncTime + 0 < osGetMilliseconds()) {
|
||||||
|
if (17 == showFaceIndex) {
|
||||||
|
if (lastShowFaceIndexIncTime + 0 < osGetMilliseconds()) {
|
||||||
if (showFaceIndex > convexHullGetFace3Num(hull)) {
|
if (showFaceIndex > convexHullGetFace3Num(hull)) {
|
||||||
showFaceIndex = 0;
|
showFaceIndex = 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -606,6 +609,15 @@ static int bmeshStichFrom(bmesh *bm, bmeshBall *parent, bmeshBall *ball) {
|
||||||
}
|
}
|
||||||
lastShowFaceIndexIncTime = osGetMilliseconds();
|
lastShowFaceIndexIncTime = osGetMilliseconds();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (showFaceIndex > convexHullGetFace3Num(hull)) {
|
||||||
|
showFaceIndex = 0;
|
||||||
|
} else {
|
||||||
|
showFaceIndex++;
|
||||||
|
}
|
||||||
|
lastShowFaceIndexIncTime = osGetMilliseconds();
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
glColor3f(1.0f, 1.0f, 1.0f);
|
glColor3f(1.0f, 1.0f, 1.0f);
|
||||||
{
|
{
|
||||||
|
@ -617,7 +629,7 @@ static int bmeshStichFrom(bmesh *bm, bmeshBall *parent, bmeshBall *ball) {
|
||||||
tri.pt[0] = *convexHullGetVertex(hull, face->indices[0]);
|
tri.pt[0] = *convexHullGetVertex(hull, face->indices[0]);
|
||||||
tri.pt[1] = *convexHullGetVertex(hull, face->indices[1]);
|
tri.pt[1] = *convexHullGetVertex(hull, face->indices[1]);
|
||||||
tri.pt[2] = *convexHullGetVertex(hull, face->indices[2]);
|
tri.pt[2] = *convexHullGetVertex(hull, face->indices[2]);
|
||||||
if (triIndex > showFaceIndex) {
|
if (triIndex >= showFaceIndex) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
drawTriangle(&tri);
|
drawTriangle(&tri);
|
||||||
|
|
216
src/convexhull.c
216
src/convexhull.c
|
@ -1,15 +1,18 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
#include "convexhull.h"
|
#include "convexhull.h"
|
||||||
#include "array.h"
|
#include "array.h"
|
||||||
#include "hashtable.h"
|
#include "hashtable.h"
|
||||||
|
#include "draw.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
// Implement Gift wrapping method which describled in http://dccg.upc.edu/people/vera/wp-content/uploads/2014/11/GA2014-ConvexHulls3D-Roger-Hernando.pdf
|
// Implement Gift wrapping method which describled in http://dccg.upc.edu/people/vera/wp-content/uploads/2014/11/GA2014-ConvexHulls3D-Roger-Hernando.pdf
|
||||||
//
|
//
|
||||||
|
|
||||||
#define TRIANGLE_INDEX_HASHTABLE_SIZE 100
|
#define FACE3_HASHTABLE_SIZE 100
|
||||||
|
#define EDGE_HASHTABLE_SIZE 100
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
vec3 pt;
|
vec3 pt;
|
||||||
|
@ -17,14 +20,25 @@ typedef struct {
|
||||||
int orderOnPlane;
|
int orderOnPlane;
|
||||||
} converHullVertex;
|
} converHullVertex;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int p1;
|
||||||
|
int p2;
|
||||||
|
int hill1;
|
||||||
|
int hill2;
|
||||||
|
vec3 hill1Normal;
|
||||||
|
} edge;
|
||||||
|
|
||||||
struct convexHull {
|
struct convexHull {
|
||||||
array *vertexArray;
|
array *vertexArray;
|
||||||
array *todoArray;
|
array *todoArray;
|
||||||
array *face3Array;
|
array *face3Array;
|
||||||
int nextTodoIndex;
|
int nextTodoIndex;
|
||||||
unsigned int *openEdgeExistMap;
|
unsigned int *openEdgeProcessedMap;
|
||||||
hashtable *face3Hashtable;
|
hashtable *face3Hashtable;
|
||||||
face3 findFace3;
|
face3 findFace3;
|
||||||
|
array *edgeArray;
|
||||||
|
hashtable *edgeHashtable;
|
||||||
|
edge findEdge;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -37,29 +51,51 @@ static int cantorPair(int k1, int k2) {
|
||||||
return (k1 + k2) * (k1 + k2 + 1) / 2 + k2;
|
return (k1 + k2) * (k1 + k2 + 1) / 2 + k2;
|
||||||
}
|
}
|
||||||
|
|
||||||
face3 *convexHullGetFaceByHashtableParam(convexHull *hull,
|
face3 *convexHullGetFaceByHashtableParam(void *userData, const void *node) {
|
||||||
const void *param) {
|
convexHull *hull = (convexHull *)userData;
|
||||||
int index = (char *)param - (char *)0;
|
int index = (char *)node - (char *)0;
|
||||||
if (0 == index) {
|
if (0 == index) {
|
||||||
return &hull->findFace3;
|
return &hull->findFace3;
|
||||||
}
|
}
|
||||||
return (face3 *)arrayGetItem(hull->face3Array, index - 1);
|
return (face3 *)arrayGetItem(hull->face3Array, index - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int faceHash(void *userData, const void *node) {
|
static int face3Hash(void *userData, const void *node) {
|
||||||
face3 *triIdx = convexHullGetFaceByHashtableParam(
|
face3 *face = convexHullGetFaceByHashtableParam(userData, node);
|
||||||
(convexHull *)userData, node);
|
return cantorPair(cantorPair(face->indices[0], face->indices[1]),
|
||||||
return cantorPair(cantorPair(triIdx->indices[0], triIdx->indices[1]),
|
face->indices[2]);
|
||||||
triIdx->indices[2]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int faceCompare(void *userData, const void *node1,
|
edge *convexHullGetEdgeByHashtableParam(void *userData, const void *node) {
|
||||||
|
convexHull *hull = (convexHull *)userData;
|
||||||
|
int index = (char *)node - (char *)0;
|
||||||
|
if (0 == index) {
|
||||||
|
return &hull->findEdge;
|
||||||
|
}
|
||||||
|
return (edge *)arrayGetItem(hull->edgeArray, index - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int edgeHash(void *userData, const void *node) {
|
||||||
|
edge *e = convexHullGetEdgeByHashtableParam(userData, node);
|
||||||
|
return e->p1 < e->p2 ? cantorPair(e->p1, e->p2) : cantorPair(e->p2, e->p1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int face3Compare(void *userData, const void *node1,
|
||||||
const void *node2) {
|
const void *node2) {
|
||||||
face3 *triIdx1 = convexHullGetFaceByHashtableParam(
|
face3 *f1 = convexHullGetFaceByHashtableParam(userData, node1);
|
||||||
(convexHull *)userData, node1);
|
face3 *f2 = convexHullGetFaceByHashtableParam(userData, node2);
|
||||||
face3 *triIdx2 = convexHullGetFaceByHashtableParam(
|
return memcmp(f1, f2, sizeof(face3));
|
||||||
(convexHull *)userData, node2);
|
}
|
||||||
return memcmp(triIdx1, triIdx2, sizeof(face3));
|
|
||||||
|
static int edgeCompare(void *userData, const void *node1,
|
||||||
|
const void *node2) {
|
||||||
|
edge *e1 = convexHullGetEdgeByHashtableParam(userData, node1);
|
||||||
|
edge *e2 = convexHullGetEdgeByHashtableParam(userData, node2);
|
||||||
|
if ((e1->p1 == e2->p1 && e1->p2 == e2->p2) ||
|
||||||
|
(e1->p2 == e2->p1 && e1->p1 == e2->p2)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
convexHull *convexHullCreate(void) {
|
convexHull *convexHullCreate(void) {
|
||||||
|
@ -86,31 +122,82 @@ convexHull *convexHullCreate(void) {
|
||||||
convexHullDestroy(hull);
|
convexHullDestroy(hull);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
hull->face3Hashtable = hashtableCreate(TRIANGLE_INDEX_HASHTABLE_SIZE,
|
hull->face3Hashtable = hashtableCreate(FACE3_HASHTABLE_SIZE,
|
||||||
faceHash, faceCompare, hull);
|
face3Hash, face3Compare, hull);
|
||||||
if (!hull->face3Hashtable) {
|
if (!hull->face3Hashtable) {
|
||||||
fprintf(stderr, "%s:hashtableCreate failed.\n", __FUNCTION__);
|
fprintf(stderr, "%s:hashtableCreate failed.\n", __FUNCTION__);
|
||||||
convexHullDestroy(hull);
|
convexHullDestroy(hull);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
hull->edgeArray = arrayCreate(sizeof(edge));
|
||||||
|
if (!hull->edgeArray) {
|
||||||
|
fprintf(stderr, "%s:arrayCreate failed.\n", __FUNCTION__);
|
||||||
|
convexHullDestroy(hull);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
hull->edgeHashtable = hashtableCreate(EDGE_HASHTABLE_SIZE,
|
||||||
|
edgeHash, edgeCompare, hull);
|
||||||
|
if (!hull->edgeHashtable) {
|
||||||
|
fprintf(stderr, "%s:hashtableCreate failed.\n", __FUNCTION__);
|
||||||
|
convexHullDestroy(hull);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return hull;
|
return hull;
|
||||||
}
|
}
|
||||||
|
|
||||||
void convexHullMarkEdgeAsExsits(convexHull *hull, int firstVertex,
|
edge *convexHullFindEdge(convexHull *hull, int p1, int p2) {
|
||||||
int secondVertex) {
|
int index;
|
||||||
int mapIndex = firstVertex * arrayGetLength(hull->vertexArray) + secondVertex;
|
hull->findEdge.p1 = p1;
|
||||||
int unitIndex = mapIndex / (sizeof(unsigned int) * 8);
|
hull->findEdge.p2 = p2;
|
||||||
int unitOffset = mapIndex % (sizeof(unsigned int) * 8);
|
index = (char *)hashtableGet(hull->edgeHashtable, 0) - (char *)0;
|
||||||
hull->openEdgeExistMap[unitIndex] |= (0x00000001 << unitOffset);
|
if (0 == index) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return arrayGetItem(hull->edgeArray, index - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int convexHullEdgeExsits(convexHull *hull, int firstVertex,
|
int convexHullAddEdge(convexHull *hull, int p1, int p2, int hill) {
|
||||||
|
edge *e = convexHullFindEdge(hull, p1, p2);
|
||||||
|
if (!e) {
|
||||||
|
int newIndex = arrayGetLength(hull->edgeArray);
|
||||||
|
if (0 != arraySetLength(hull->edgeArray, newIndex + 1)) {
|
||||||
|
fprintf(stderr, "%s:arraySetLength failed.\n", __FUNCTION__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
e = (edge *)arrayGetItem(hull->edgeArray, newIndex);
|
||||||
|
e->p1 = p1;
|
||||||
|
e->p2 = p2;
|
||||||
|
e->hill1 = hill;
|
||||||
|
e->hill2 = -1;
|
||||||
|
vec3Normal((vec3 *)arrayGetItem(hull->vertexArray, e->p1),
|
||||||
|
(vec3 *)arrayGetItem(hull->vertexArray, e->p2),
|
||||||
|
(vec3 *)arrayGetItem(hull->vertexArray, e->hill1), &e->hill1Normal);
|
||||||
|
if (0 != hashtableInsert(hull->edgeHashtable, (char *)0 + newIndex + 1)) {
|
||||||
|
fprintf(stderr, "%s:hashtableInsert failed.\n", __FUNCTION__);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
assert(-1 == e->hill2);
|
||||||
|
e->hill2 = hill;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void convexHullMarkEdgeAsProcessed(convexHull *hull, int firstVertex,
|
||||||
int secondVertex) {
|
int secondVertex) {
|
||||||
if (hull->openEdgeExistMap) {
|
|
||||||
int mapIndex = firstVertex * arrayGetLength(hull->vertexArray) + secondVertex;
|
int mapIndex = firstVertex * arrayGetLength(hull->vertexArray) + secondVertex;
|
||||||
int unitIndex = mapIndex / (sizeof(unsigned int) * 8);
|
int unitIndex = mapIndex / (sizeof(unsigned int) * 8);
|
||||||
int unitOffset = mapIndex % (sizeof(unsigned int) * 8);
|
int unitOffset = mapIndex % (sizeof(unsigned int) * 8);
|
||||||
return hull->openEdgeExistMap[unitIndex] & (0x00000001 << unitOffset);
|
hull->openEdgeProcessedMap[unitIndex] |= (0x00000001 << unitOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
int convexHullOpenEdgeProcessed(convexHull *hull, int firstVertex,
|
||||||
|
int secondVertex) {
|
||||||
|
if (hull->openEdgeProcessedMap) {
|
||||||
|
int mapIndex = firstVertex * arrayGetLength(hull->vertexArray) + secondVertex;
|
||||||
|
int unitIndex = mapIndex / (sizeof(unsigned int) * 8);
|
||||||
|
int unitOffset = mapIndex % (sizeof(unsigned int) * 8);
|
||||||
|
return hull->openEdgeProcessedMap[unitIndex] & (0x00000001 << unitOffset);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -214,26 +301,28 @@ int convexHullAddFace3(convexHull *hull, int firstVertex, int secondVertex,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void convexHullReleaseForGenerate(convexHull *hull) {
|
static void convexHullReleaseForGenerate(convexHull *hull) {
|
||||||
free(hull->openEdgeExistMap);
|
free(hull->openEdgeProcessedMap);
|
||||||
hull->openEdgeExistMap = 0;
|
hull->openEdgeProcessedMap = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void convexHullDestroy(convexHull *hull) {
|
void convexHullDestroy(convexHull *hull) {
|
||||||
arrayDestroy(hull->vertexArray);
|
arrayDestroy(hull->vertexArray);
|
||||||
arrayDestroy(hull->todoArray);
|
arrayDestroy(hull->todoArray);
|
||||||
arrayDestroy(hull->face3Array);
|
arrayDestroy(hull->face3Array);
|
||||||
|
arrayDestroy(hull->edgeArray);
|
||||||
|
hashtableDestroy(hull->edgeHashtable);
|
||||||
hashtableDestroy(hull->face3Hashtable);
|
hashtableDestroy(hull->face3Hashtable);
|
||||||
convexHullReleaseForGenerate(hull);
|
convexHullReleaseForGenerate(hull);
|
||||||
free(hull);
|
free(hull);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int convexHullPrepareForGenerate(convexHull *hull) {
|
static int convexHullPrepareForGenerate(convexHull *hull) {
|
||||||
free(hull->openEdgeExistMap);
|
free(hull->openEdgeProcessedMap);
|
||||||
hull->openEdgeExistMap = (unsigned int *)calloc(
|
hull->openEdgeProcessedMap = (unsigned int *)calloc(
|
||||||
arrayGetLength(hull->vertexArray) * arrayGetLength(hull->vertexArray) /
|
arrayGetLength(hull->vertexArray) * arrayGetLength(hull->vertexArray) /
|
||||||
(sizeof(unsigned int) * 8) + 1,
|
(sizeof(unsigned int) * 8) + 1,
|
||||||
sizeof(unsigned int));
|
sizeof(unsigned int));
|
||||||
if (!hull->openEdgeExistMap) {
|
if (!hull->openEdgeProcessedMap) {
|
||||||
fprintf(stderr, "%s:Insufficient memory.\n", __FUNCTION__);
|
fprintf(stderr, "%s:Insufficient memory.\n", __FUNCTION__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -272,12 +361,57 @@ int convexHullGetNextVertex(convexHull *hull, int p1Index, int p2Index,
|
||||||
|
|
||||||
int convexHullAddTodo(convexHull *hull, int vertex1, int vertex2,
|
int convexHullAddTodo(convexHull *hull, int vertex1, int vertex2,
|
||||||
int vertex3) {
|
int vertex3) {
|
||||||
if (!convexHullEdgeExsits(hull, vertex1, vertex2)) {
|
if (!convexHullOpenEdgeProcessed(hull, vertex1, vertex2)) {
|
||||||
return convexHullAddTodoNoCheck(hull, vertex1, vertex2, vertex3);
|
return convexHullAddTodoNoCheck(hull, vertex1, vertex2, vertex3);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern int showFaceIndex;
|
||||||
|
|
||||||
|
static int convexHullCanAddFace3(convexHull *hull, int index1, int index2,
|
||||||
|
int index3) {
|
||||||
|
int i;
|
||||||
|
int indices[] = {index1, index2, index3};
|
||||||
|
|
||||||
|
if (showFaceIndex == arrayGetLength(hull->face3Array)) {
|
||||||
|
drawDebugPrintf("showFaceIndex:%d can add (%d,%d,%d)", showFaceIndex,
|
||||||
|
index1, index2, index3);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 3; ++i) {
|
||||||
|
int p1 = indices[i];
|
||||||
|
int p2 = indices[(i + 1) % 3];
|
||||||
|
int hill = indices[(i + 2) % 3];
|
||||||
|
float angle;
|
||||||
|
edge *e = convexHullFindEdge(hull, p1, p2);
|
||||||
|
if (e) {
|
||||||
|
vec3 normal;
|
||||||
|
if (-1 != e->hill2) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
vec3Normal((vec3 *)arrayGetItem(hull->vertexArray, e->p1),
|
||||||
|
(vec3 *)arrayGetItem(hull->vertexArray, e->p2),
|
||||||
|
(vec3 *)arrayGetItem(hull->vertexArray, hill), &normal);
|
||||||
|
angle = vec3Angle(&e->hill1Normal, &normal);
|
||||||
|
|
||||||
|
if (showFaceIndex == arrayGetLength(hull->face3Array)) {
|
||||||
|
drawDebugPrintf("showFaceIndex:%d angle:%f (%d,%d,%d)",
|
||||||
|
showFaceIndex, angle, e->p1, e->p2, e->hill1);
|
||||||
|
drawSphere((vec3 *)arrayGetItem(hull->vertexArray, 9),
|
||||||
|
0.1, 36, 24);
|
||||||
|
drawSphere((vec3 *)arrayGetItem(hull->vertexArray, 6),
|
||||||
|
0.1, 36, 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (angle < 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int convexHullGenerate(convexHull *hull) {
|
int convexHullGenerate(convexHull *hull) {
|
||||||
int index1, index2, index3;
|
int index1, index2, index3;
|
||||||
convexHullReleaseForGenerate(hull);
|
convexHullReleaseForGenerate(hull);
|
||||||
|
@ -289,15 +423,25 @@ int convexHullGenerate(convexHull *hull) {
|
||||||
todo *t = (todo *)arrayGetItem(hull->todoArray, hull->nextTodoIndex++);
|
todo *t = (todo *)arrayGetItem(hull->todoArray, hull->nextTodoIndex++);
|
||||||
index1 = t->firstVertex;
|
index1 = t->firstVertex;
|
||||||
index2 = t->secondVertex;
|
index2 = t->secondVertex;
|
||||||
if (convexHullEdgeExsits(hull, index1, index2) ||
|
if (convexHullOpenEdgeProcessed(hull, index1, index2) ||
|
||||||
convexHullEdgeExsits(hull, index2, index1)) {
|
convexHullOpenEdgeProcessed(hull, index2, index1)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
convexHullMarkEdgeAsExsits(hull, index1, index2);
|
convexHullMarkEdgeAsProcessed(hull, index1, index2);
|
||||||
index3 = convexHullGetNextVertex(hull, index1, index2, t->thirdVertex);
|
index3 = convexHullGetNextVertex(hull, index1, index2, t->thirdVertex);
|
||||||
if (-1 == index3) {
|
if (-1 == index3) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (!convexHullCanAddFace3(hull, index1, index2, index3)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (showFaceIndex == arrayGetLength(hull->face3Array)) {
|
||||||
|
drawDebugPrintf("showFaceIndex:%d added face3 (%d,%d,%d)",
|
||||||
|
showFaceIndex, index1, index2, index3);
|
||||||
|
}
|
||||||
|
convexHullAddEdge(hull, index1, index2, index3);
|
||||||
|
convexHullAddEdge(hull, index2, index3, index1);
|
||||||
|
convexHullAddEdge(hull, index3, index1, index2);
|
||||||
convexHullAddFace3(hull, index1, index2, index3);
|
convexHullAddFace3(hull, index1, index2, index3);
|
||||||
convexHullAddTodo(hull, index2, index3, index1);
|
convexHullAddTodo(hull, index2, index3, index1);
|
||||||
convexHullAddTodo(hull, index3, index1, index2);
|
convexHullAddTodo(hull, index3, index1, index2);
|
||||||
|
|
Loading…
Reference in New Issue