use convhull_3d for quicker hull calculation

This commit is contained in:
Garux 2018-10-22 18:36:38 +03:00
parent 1191f54ef4
commit 736f89026f
2 changed files with 107 additions and 301 deletions

View File

@ -1,16 +1,16 @@
/* /*
Copyright (c) 2017-2018 Leo McCormack Copyright (c) 2017-2018 Leo McCormack
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software. all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -57,7 +57,7 @@
extern "C" { extern "C" {
#endif #endif
#ifdef CONVHULL_3D_USE_FLOAT_PRECISION #ifdef CONVHULL_3D_USE_FLOAT_PRECISION
typedef float CH_FLOAT; typedef float CH_FLOAT;
#else #else
@ -72,7 +72,7 @@ typedef struct _ch_vertex {
}; };
} ch_vertex; } ch_vertex;
typedef ch_vertex ch_vec3; typedef ch_vertex ch_vec3;
/* builds the convexhull, returning the face indices corresponding to "in_vertices" */ /* builds the convexhull, returning the face indices corresponding to "in_vertices" */
void convhull_3d_build(/* input arguments */ void convhull_3d_build(/* input arguments */
ch_vertex* const in_vertices, /* vector of input vertices; nVert x 1 */ ch_vertex* const in_vertices, /* vector of input vertices; nVert x 1 */
@ -80,30 +80,6 @@ void convhull_3d_build(/* input arguments */
/* output arguments */ /* output arguments */
int** out_faces, /* & of empty int*, output face indices; flat: nOut_faces x 3 */ int** out_faces, /* & of empty int*, output face indices; flat: nOut_faces x 3 */
int* nOut_faces); /* & of int, number of output face indices */ int* nOut_faces); /* & of int, number of output face indices */
/* exports the vertices, face indices, and face normals, as an 'obj' file, ready for GPU */
void convhull_3d_export_obj(/* input arguments */
ch_vertex* const vertices, /* vector of input vertices; nVert x 1 */
const int nVert, /* number of vertices */
int* const faces, /* face indices; flat: nFaces x 3 */
const int nFaces, /* number of faces in hull */
const int keepOnlyUsedVerticesFLAG, /* 0: exports in_vertices, 1: exports only used vertices */
char* const obj_filename); /* obj filename, WITHOUT extension */
/* exports the vertices, face indices, and face normals, as an 'm' file, for MatLab verification */
void convhull_3d_export_m(/* input arguments */
ch_vertex* const vertices, /* vector of input vertices; nVert x 1 */
const int nVert, /* number of vertices */
int* const faces, /* face indices; flat: nFaces x 3 */
const int nFaces, /* number of faces in hull */
char* const m_filename); /* m filename, WITHOUT extension */
/* reads an 'obj' file and extracts only the vertices */
void extractVerticesFromObjFile(/* input arguments */
char* const obj_filename, /* obj filename, WITHOUT extension */
/* output arguments */
ch_vertex** out_vertices, /* & of empty ch_vertex*, output vertices; out_nVert x 1 */
int* out_nVert); /* & of int, number of vertices */
#ifdef __cplusplus #ifdef __cplusplus
} /*extern "C"*/ } /*extern "C"*/
@ -116,22 +92,11 @@ void extractVerticesFromObjFile(/* input arguments */
* INTERNAL: * INTERNAL:
***********/ ***********/
#ifdef CONVHULL_3D_ENABLE
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include <math.h> #include <math.h>
#include <string.h> #include <string.h>
#include <float.h> #include <float.h>
#include <ctype.h> #include <ctype.h>
#include <string.h>
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
#define CV_STRNCPY(a,b,c) strncpy_s(a,c+1,b,c);
#define CV_STRCAT(a,b) strcat_s(a,sizeof(b),b);
#else
#define CV_STRNCPY(a,b,c) strncpy(a,b,c);
#define CV_STRCAT(a,b) strcat(a,b);
#endif
#ifdef CONVHULL_3D_USE_FLOAT_PRECISION #ifdef CONVHULL_3D_USE_FLOAT_PRECISION
#define CH_FLT_MIN FLT_MIN #define CH_FLT_MIN FLT_MIN
#define CH_FLT_MAX FLT_MAX #define CH_FLT_MAX FLT_MAX
@ -167,39 +132,38 @@ static int cmp_asc_int(const void*, const void*);
static int cmp_desc_int(const void*, const void*); static int cmp_desc_int(const void*, const void*);
static void sort_float(CH_FLOAT*, CH_FLOAT*, int*, int, int); static void sort_float(CH_FLOAT*, CH_FLOAT*, int*, int, int);
static void sort_int(int*, int*, int*, int, int); static void sort_int(int*, int*, int*, int, int);
static ch_vec3 cross(ch_vec3*, ch_vec3*);
static CH_FLOAT det_4x4(CH_FLOAT*); static CH_FLOAT det_4x4(CH_FLOAT*);
static void plane_3d(CH_FLOAT*, CH_FLOAT*, CH_FLOAT*); static void plane_3d(CH_FLOAT*, CH_FLOAT*, CH_FLOAT*);
static void ismember(int*, int*, int*, int, int); static void ismember(int*, int*, int*, int, int);
/* internal functions definitions: */ /* internal functions definitions: */
static int cmp_asc_float(const void *a,const void *b) { static int cmp_asc_float(const void *a,const void *b) {
struct float_w_idx *a1 = (struct float_w_idx*)a; const struct float_w_idx *a1 = (const struct float_w_idx*)a;
struct float_w_idx *a2 = (struct float_w_idx*)b; const struct float_w_idx *a2 = (const struct float_w_idx*)b;
if((*a1).val<(*a2).val)return -1; if((*a1).val<(*a2).val)return -1;
else if((*a1).val>(*a2).val)return 1; else if((*a1).val>(*a2).val)return 1;
else return 0; else return 0;
} }
static int cmp_desc_float(const void *a,const void *b) { static int cmp_desc_float(const void *a,const void *b) {
struct float_w_idx *a1 = (struct float_w_idx*)a; const struct float_w_idx *a1 = (const struct float_w_idx*)a;
struct float_w_idx *a2 = (struct float_w_idx*)b; const struct float_w_idx *a2 = (const struct float_w_idx*)b;
if((*a1).val>(*a2).val)return -1; if((*a1).val>(*a2).val)return -1;
else if((*a1).val<(*a2).val)return 1; else if((*a1).val<(*a2).val)return 1;
else return 0; else return 0;
} }
static int cmp_asc_int(const void *a,const void *b) { static int cmp_asc_int(const void *a,const void *b) {
struct int_w_idx *a1 = (struct int_w_idx*)a; const struct int_w_idx *a1 = (const struct int_w_idx*)a;
struct int_w_idx *a2 = (struct int_w_idx*)b; const struct int_w_idx *a2 = (const struct int_w_idx*)b;
if((*a1).val<(*a2).val)return -1; if((*a1).val<(*a2).val)return -1;
else if((*a1).val>(*a2).val)return 1; else if((*a1).val>(*a2).val)return 1;
else return 0; else return 0;
} }
static int cmp_desc_int(const void *a,const void *b) { static int cmp_desc_int(const void *a,const void *b) {
struct int_w_idx *a1 = (struct int_w_idx*)a; const struct int_w_idx *a1 = (const struct int_w_idx*)a;
struct int_w_idx *a2 = (struct int_w_idx*)b; const struct int_w_idx *a2 = (const struct int_w_idx*)b;
if((*a1).val>(*a2).val)return -1; if((*a1).val>(*a2).val)return -1;
else if((*a1).val<(*a2).val)return 1; else if((*a1).val<(*a2).val)return 1;
else return 0; else return 0;
@ -216,7 +180,7 @@ static void sort_float
{ {
int i; int i;
struct float_w_idx *data; struct float_w_idx *data;
data = (float_w_idx*)malloc(len*sizeof(float_w_idx)); data = (float_w_idx*)malloc(len*sizeof(float_w_idx));
for(i=0;i<len;i++) { for(i=0;i<len;i++) {
data[i].val=in_vec[i]; data[i].val=in_vec[i];
@ -248,7 +212,7 @@ static void sort_int
{ {
int i; int i;
struct int_w_idx *data; struct int_w_idx *data;
data = (int_w_idx*)malloc(len*sizeof(int_w_idx)); data = (int_w_idx*)malloc(len*sizeof(int_w_idx));
for(i=0;i<len;i++) { for(i=0;i<len;i++) {
data[i].val=in_vec[i]; data[i].val=in_vec[i];
@ -269,15 +233,6 @@ static void sort_int
free(data); free(data);
} }
static ch_vec3 cross(ch_vec3* v1, ch_vec3* v2)
{
ch_vec3 cross;
cross.x = v1->y * v2->z - v1->z * v2->y;
cross.y = v1->z * v2->x - v1->x * v2->z;
cross.z = v1->x * v2->y - v1->y * v2->x;
return cross;
}
/* calculates the determinent of a 4x4 matrix */ /* calculates the determinent of a 4x4 matrix */
static CH_FLOAT det_4x4(CH_FLOAT* m) { static CH_FLOAT det_4x4(CH_FLOAT* m) {
return return
@ -310,7 +265,7 @@ static void plane_3d
int r[3]; int r[3];
CH_FLOAT sign, det, norm_c; CH_FLOAT sign, det, norm_c;
CH_FLOAT pdiff[2][3], pdiff_s[2][2]; CH_FLOAT pdiff[2][3], pdiff_s[2][2];
for(i=0; i<2; i++) for(i=0; i<2; i++)
for(j=0; j<3; j++) for(j=0; j<3; j++)
pdiff[i][j] = p[(i+1)*3+j] - p[i*3+j]; pdiff[i][j] = p[(i+1)*3+j] - p[i*3+j];
@ -380,13 +335,13 @@ void convhull_3d_build
int* aVec, *faces; int* aVec, *faces;
CH_FLOAT dfi, v, max_p, min_p; CH_FLOAT dfi, v, max_p, min_p;
CH_FLOAT* points, *cf, *cfi, *df, *p_s, *span; CH_FLOAT* points, *cf, *cfi, *df, *p_s, *span;
if(nVert<3 || in_vertices==NULL){ if(nVert<3 || in_vertices==NULL){
(*out_faces) = NULL; (*out_faces) = NULL;
(*nOut_faces) = 0; (*nOut_faces) = 0;
return; return;
} }
/* 3 dimensions. The code should theoretically work for >=2 dimensions, but "plane_3d" and "det_4x4" are hardcoded for 3, /* 3 dimensions. The code should theoretically work for >=2 dimensions, but "plane_3d" and "det_4x4" are hardcoded for 3,
* so would need to be rewritten */ * so would need to be rewritten */
d = 3; d = 3;
@ -405,14 +360,14 @@ void convhull_3d_build
points[i*(d+1)+j] = in_vertices[i].v[j] + CH_NOISE_VAL*rand()/(float)RAND_MAX; /* noise mitigates duplicates */ points[i*(d+1)+j] = in_vertices[i].v[j] + CH_NOISE_VAL*rand()/(float)RAND_MAX; /* noise mitigates duplicates */
points[i*(d+1)+d] = 1.0f; /* add a last column of ones. Used only for determinant calculation */ points[i*(d+1)+d] = 1.0f; /* add a last column of ones. Used only for determinant calculation */
} }
/* The initial convex hull is a simplex with (d+1) facets, where d is the number of dimensions */ /* The initial convex hull is a simplex with (d+1) facets, where d is the number of dimensions */
nFaces = (d+1); nFaces = (d+1);
faces = (int*)calloc(nFaces*d, sizeof(int)); faces = (int*)calloc(nFaces*d, sizeof(int));
aVec = (int*)malloc(nFaces*sizeof(int)); aVec = (int*)malloc(nFaces*sizeof(int));
for(i=0; i<nFaces; i++) for(i=0; i<nFaces; i++)
aVec[i] = i; aVec[i] = i;
/* Each column of cf contains the coefficients of a plane */ /* Each column of cf contains the coefficients of a plane */
cf = (CH_FLOAT*)malloc(nFaces*d*sizeof(CH_FLOAT)); cf = (CH_FLOAT*)malloc(nFaces*d*sizeof(CH_FLOAT));
cfi = (CH_FLOAT*)malloc(d*sizeof(CH_FLOAT)); cfi = (CH_FLOAT*)malloc(d*sizeof(CH_FLOAT));
@ -426,12 +381,12 @@ void convhull_3d_build
k++; k++;
} }
} }
/* Calculate and store the plane coefficients of the face */ /* Calculate and store the plane coefficients of the face */
for(j=0; j<d; j++) for(j=0; j<d; j++)
for(k=0; k<d; k++) for(k=0; k<d; k++)
p_s[j*d+k] = points[(faces[i*d+j])*(d+1) + k]; p_s[j*d+k] = points[(faces[i*d+j])*(d+1) + k];
/* Calculate and store the plane coefficients of the face */ /* Calculate and store the plane coefficients of the face */
plane_3d(p_s, cfi, &dfi); plane_3d(p_s, cfi, &dfi);
for(j=0; j<d; j++) for(j=0; j<d; j++)
@ -440,12 +395,12 @@ void convhull_3d_build
} }
CH_FLOAT *A; CH_FLOAT *A;
int *bVec, *fVec, *asfVec, *face_tmp; int *bVec, *fVec, *asfVec, *face_tmp;
/* Check to make sure that faces are correctly oriented */ /* Check to make sure that faces are correctly oriented */
bVec = (int*)malloc(4*sizeof(int)); bVec = (int*)malloc(4*sizeof(int));
for(i=0; i<d+1; i++) for(i=0; i<d+1; i++)
bVec[i] = i; bVec[i] = i;
/* A contains the coordinates of the points forming a simplex */ /* A contains the coordinates of the points forming a simplex */
A = (CH_FLOAT*)calloc((d+1)*(d+1), sizeof(CH_FLOAT)); A = (CH_FLOAT*)calloc((d+1)*(d+1), sizeof(CH_FLOAT));
face_tmp = (int*)malloc((d+1)*sizeof(int)); face_tmp = (int*)malloc((d+1)*sizeof(int));
@ -463,10 +418,10 @@ void convhull_3d_build
for(; i<(d+1); i++) for(; i<(d+1); i++)
for(j=0; j<(d+1); j++) for(j=0; j<(d+1); j++)
A[i*(d+1)+j] = points[p*(d+1)+j]; A[i*(d+1)+j] = points[p*(d+1)+j];
/* det(A) determines the orientation of the face */ /* det(A) determines the orientation of the face */
v = det_4x4(A); v = det_4x4(A);
/* Orient so that each point on the original simplex can't see the opposite face */ /* Orient so that each point on the original simplex can't see the opposite face */
if(v<0){ if(v<0){
/* Reverse the order of the last two vertices to change the volume */ /* Reverse the order of the last two vertices to change the volume */
@ -474,7 +429,7 @@ void convhull_3d_build
face_tmp[j] = faces[k*d+j]; face_tmp[j] = faces[k*d+j];
for(j=0, l=d-2; j<d-1; j++, l++) for(j=0, l=d-2; j<d-1; j++, l++)
faces[k*d+l] = face_tmp[d-j-1]; faces[k*d+l] = face_tmp[d-j-1];
/* Modify the plane coefficients of the properly oriented faces */ /* Modify the plane coefficients of the properly oriented faces */
for(j=0; j<d; j++) for(j=0; j<d; j++)
cf[k*d+j] = -cf[k*d+j]; cf[k*d+j] = -cf[k*d+j];
@ -487,7 +442,7 @@ void convhull_3d_build
A[i*(d+1)+j] = points[p*(d+1)+j]; A[i*(d+1)+j] = points[p*(d+1)+j];
} }
} }
/* Coordinates of the center of the point set */ /* Coordinates of the center of the point set */
CH_FLOAT* meanp, *absdist, *reldist, *desReldist; CH_FLOAT* meanp, *absdist, *reldist, *desReldist;
meanp = (CH_FLOAT*)calloc(d, sizeof(CH_FLOAT)); meanp = (CH_FLOAT*)calloc(d, sizeof(CH_FLOAT));
@ -496,41 +451,41 @@ void convhull_3d_build
meanp[j] += points[i*(d+1)+j]; meanp[j] += points[i*(d+1)+j];
for(j=0; j<d; j++) for(j=0; j<d; j++)
meanp[j] = meanp[j]/(CH_FLOAT)(nVert-d-1); meanp[j] = meanp[j]/(CH_FLOAT)(nVert-d-1);
/* Absolute distance of points from the center */ /* Absolute distance of points from the center */
absdist = (CH_FLOAT*)malloc((nVert-d-1)*d * sizeof(CH_FLOAT)); absdist = (CH_FLOAT*)malloc((nVert-d-1)*d * sizeof(CH_FLOAT));
for(i=d+1, k=0; i<nVert; i++, k++) for(i=d+1, k=0; i<nVert; i++, k++)
for(j=0; j<d; j++) for(j=0; j<d; j++)
absdist[k*d+j] = (points[i*(d+1)+j] - meanp[j])/span[j]; absdist[k*d+j] = (points[i*(d+1)+j] - meanp[j])/span[j];
/* Relative distance of points from the center */ /* Relative distance of points from the center */
reldist = (CH_FLOAT*)calloc((nVert-d-1), sizeof(CH_FLOAT)); reldist = (CH_FLOAT*)calloc((nVert-d-1), sizeof(CH_FLOAT));
desReldist = (CH_FLOAT*)malloc((nVert-d-1) * sizeof(CH_FLOAT)); desReldist = (CH_FLOAT*)malloc((nVert-d-1) * sizeof(CH_FLOAT));
for(i=0; i<(nVert-d-1); i++) for(i=0; i<(nVert-d-1); i++)
for(j=0; j<d; j++) for(j=0; j<d; j++)
reldist[i] += pow(absdist[i*d+j], 2.0); reldist[i] += pow(absdist[i*d+j], 2.0);
/* Sort from maximum to minimum relative distance */ /* Sort from maximum to minimum relative distance */
int num_pleft, cnt; int num_pleft, cnt;
int* ind, *pleft; int* ind, *pleft;
ind = (int*)malloc((nVert-d-1) * sizeof(int)); ind = (int*)malloc((nVert-d-1) * sizeof(int));
pleft = (int*)malloc((nVert-d-1) * sizeof(int)); pleft = (int*)malloc((nVert-d-1) * sizeof(int));
sort_float(reldist, desReldist, ind, (nVert-d-1), 1); sort_float(reldist, desReldist, ind, (nVert-d-1), 1);
/* Initialize the vector of points left. The points with the larger relative /* Initialize the vector of points left. The points with the larger relative
distance from the center are scanned first. */ distance from the center are scanned first. */
num_pleft = (nVert-d-1); num_pleft = (nVert-d-1);
for(i=0; i<num_pleft; i++) for(i=0; i<num_pleft; i++)
pleft[i] = ind[i]+d+1; pleft[i] = ind[i]+d+1;
/* Loop over all remaining points that are not deleted. Deletion of points /* Loop over all remaining points that are not deleted. Deletion of points
occurs every #iter2del# iterations of this while loop */ occurs every #iter2del# iterations of this while loop */
memset(A, 0, (d+1)*(d+1) * sizeof(CH_FLOAT)); memset(A, 0, (d+1)*(d+1) * sizeof(CH_FLOAT));
/* cnt is equal to the points having been selected without deletion of /* cnt is equal to the points having been selected without deletion of
nonvisible points (i.e. points inside the current convex hull) */ nonvisible points (i.e. points inside the current convex hull) */
cnt=0; cnt=0;
/* The main loop for the quickhull algorithm */ /* The main loop for the quickhull algorithm */
CH_FLOAT detA; CH_FLOAT detA;
CH_FLOAT* points_cf, *points_s; CH_FLOAT* points_cf, *points_s;
@ -549,7 +504,7 @@ void convhull_3d_build
while( (num_pleft>0) ){ while( (num_pleft>0) ){
/* i is the first point of the points left */ /* i is the first point of the points left */
i = pleft[0]; i = pleft[0];
/* Delete the point selected */ /* Delete the point selected */
for(j=0; j<num_pleft-1; j++) for(j=0; j<num_pleft-1; j++)
pleft[j] = pleft[j+1]; pleft[j] = pleft[j+1];
@ -558,10 +513,10 @@ void convhull_3d_build
free(pleft); free(pleft);
else else
pleft = (int*)realloc(pleft, num_pleft*sizeof(int)); pleft = (int*)realloc(pleft, num_pleft*sizeof(int));
/* Update point selection counter */ /* Update point selection counter */
cnt++; cnt++;
/* find visible faces */ /* find visible faces */
for(j=0; j<d; j++) for(j=0; j<d; j++)
points_s[j] = points[i*(d+1)+j]; points_s[j] = points[i*(d+1)+j];
@ -596,7 +551,7 @@ void convhull_3d_build
visible_ind[j] = 0; visible_ind[j] = 0;
} }
num_nonvisible_faces = nFaces - num_visible_ind; num_nonvisible_faces = nFaces - num_visible_ind;
/* proceed if there are any visible faces */ /* proceed if there are any visible faces */
if(num_visible_ind!=0){ if(num_visible_ind!=0){
/* Find visible face indices */ /* Find visible face indices */
@ -607,7 +562,7 @@ void convhull_3d_build
k++; k++;
} }
} }
/* Find nonvisible faces */ /* Find nonvisible faces */
nonvisible_faces = (int*)malloc(num_nonvisible_faces*d*sizeof(int)); nonvisible_faces = (int*)malloc(num_nonvisible_faces*d*sizeof(int));
f0 = (int*)malloc(num_nonvisible_faces*d*sizeof(int)); f0 = (int*)malloc(num_nonvisible_faces*d*sizeof(int));
@ -618,7 +573,7 @@ void convhull_3d_build
k++; k++;
} }
} }
/* Create horizon (count is the number of the edges of the horizon) */ /* Create horizon (count is the number of the edges of the horizon) */
count=0; count=0;
for(j=0; j<num_visible_ind; j++){ for(j=0; j<num_visible_ind; j++){
@ -629,7 +584,7 @@ void convhull_3d_build
sort_int(face_s, NULL, NULL, d, 0); sort_int(face_s, NULL, NULL, d, 0);
ismember(nonvisible_faces, face_s, f0, num_nonvisible_faces*d, d); ismember(nonvisible_faces, face_s, f0, num_nonvisible_faces*d, d);
u_len = 0; u_len = 0;
/* u are the nonvisible faces connected to the face v, if any */ /* u are the nonvisible faces connected to the face v, if any */
for(k=0; k<num_nonvisible_faces; k++){ for(k=0; k<num_nonvisible_faces; k++){
f0_sum = 0; f0_sum = 0;
@ -669,7 +624,7 @@ void convhull_3d_build
/* Delete visible faces */ /* Delete visible faces */
for(k=0; k<d; k++) for(k=0; k<d; k++)
faces[l*d+k] = faces[j*d+k]; faces[l*d+k] = faces[j*d+k];
/* Delete the corresponding plane coefficients of the faces */ /* Delete the corresponding plane coefficients of the faces */
for(k=0; k<d; k++) for(k=0; k<d; k++)
cf[l*d+k] = cf[j*d+k]; cf[l*d+k] = cf[j*d+k];
@ -677,16 +632,16 @@ void convhull_3d_build
l++; l++;
} }
} }
/* Update the number of faces */ /* Update the number of faces */
nFaces = nFaces-num_visible_ind; nFaces = nFaces-num_visible_ind;
faces = (int*)realloc(faces, nFaces*d*sizeof(int)); faces = (int*)realloc(faces, nFaces*d*sizeof(int));
cf = (CH_FLOAT*)realloc(cf, nFaces*d*sizeof(CH_FLOAT)); cf = (CH_FLOAT*)realloc(cf, nFaces*d*sizeof(CH_FLOAT));
df = (CH_FLOAT*)realloc(df, nFaces*sizeof(CH_FLOAT)); df = (CH_FLOAT*)realloc(df, nFaces*sizeof(CH_FLOAT));
/* start is the first row of the new faces */ /* start is the first row of the new faces */
start=nFaces; start=nFaces;
/* Add faces connecting horizon to the new point */ /* Add faces connecting horizon to the new point */
n_newfaces = horizon_size1; n_newfaces = horizon_size1;
for(j=0; j<n_newfaces; j++){ for(j=0; j<n_newfaces; j++){
@ -697,7 +652,7 @@ void convhull_3d_build
for(k=0; k<d-1; k++) for(k=0; k<d-1; k++)
faces[(nFaces-1)*d+k] = horizon[j*(d-1)+k]; faces[(nFaces-1)*d+k] = horizon[j*(d-1)+k];
faces[(nFaces-1)*d+(d-1)] = i; faces[(nFaces-1)*d+(d-1)] = i;
/* Calculate and store appropriately the plane coefficients of the faces */ /* Calculate and store appropriately the plane coefficients of the faces */
for(k=0; k<d; k++) for(k=0; k<d; k++)
for(l=0; l<d; l++) for(l=0; l<d; l++)
@ -712,7 +667,7 @@ void convhull_3d_build
break; break;
} }
} }
/* Orient each new face properly */ /* Orient each new face properly */
hVec = (int*)malloc( nFaces*sizeof(int)); hVec = (int*)malloc( nFaces*sizeof(int));
hVec_mem_face = (int*)malloc( nFaces*sizeof(int)); hVec_mem_face = (int*)malloc( nFaces*sizeof(int));
@ -736,7 +691,7 @@ void convhull_3d_build
} }
index = 0; index = 0;
detA = 0.0; detA = 0.0;
/* While new point is coplanar, choose another point */ /* While new point is coplanar, choose another point */
while(detA==0.0){ while(detA==0.0){
for(j=0;j<d; j++) for(j=0;j<d; j++)
@ -748,7 +703,7 @@ void convhull_3d_build
index++; index++;
detA = det_4x4(A); detA = det_4x4(A);
} }
/* Orient faces so that each point on the original simplex can't see the opposite face */ /* Orient faces so that each point on the original simplex can't see the opposite face */
if (detA<0.0){ if (detA<0.0){
/* If orientation is improper, reverse the order to change the volume sign */ /* If orientation is improper, reverse the order to change the volume sign */
@ -756,7 +711,7 @@ void convhull_3d_build
face_tmp[j] = faces[k*d+j]; face_tmp[j] = faces[k*d+j];
for(j=0, l=d-2; j<d-1; j++, l++) for(j=0, l=d-2; j<d-1; j++, l++)
faces[k*d+l] = face_tmp[d-j-1]; faces[k*d+l] = face_tmp[d-j-1];
/* Modify the plane coefficients of the properly oriented faces */ /* Modify the plane coefficients of the properly oriented faces */
for(j=0; j<d; j++) for(j=0; j<d; j++)
cf[k*d+j] = -cf[k*d+j]; cf[k*d+j] = -cf[k*d+j];
@ -781,7 +736,7 @@ void convhull_3d_build
break; break;
} }
} }
/* output */ /* output */
if(FUCKED){ if(FUCKED){
(*out_faces) = NULL; (*out_faces) = NULL;
@ -792,7 +747,7 @@ void convhull_3d_build
memcpy((*out_faces),faces, nFaces*d*sizeof(int)); memcpy((*out_faces),faces, nFaces*d*sizeof(int));
(*nOut_faces) = nFaces; (*nOut_faces) = nFaces;
} }
/* clean-up */ /* clean-up */
free(visible_ind); free(visible_ind);
free(points_cf); free(points_cf);
@ -819,178 +774,5 @@ void convhull_3d_build
free(A); free(A);
} }
void convhull_3d_export_obj
(
ch_vertex* const vertices,
const int nVert,
int* const faces,
const int nFaces,
const int keepOnlyUsedVerticesFLAG,
char* const obj_filename
)
{
int i, j;
char path[256] = "\0";
CV_STRNCPY(path, obj_filename, strlen(obj_filename));
FILE* obj_file;
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
CV_STRCAT(path, ".obj");
fopen_s(&obj_file, path, "wt");
#else
obj_file = fopen(strcat(path, ".obj"), "wt");
#endif
fprintf(obj_file, "o\n");
CH_FLOAT scale;
ch_vec3 v1, v2, normal;
/* export vertices */
if(keepOnlyUsedVerticesFLAG){
for (i = 0; i < nFaces; i++)
for(j=0; j<3; j++)
fprintf(obj_file, "v %f %f %f\n", vertices[faces[i*3+j]].x,
vertices[faces[i*3+j]].y, vertices[faces[i*3+j]].z);
}
else {
for (i = 0; i < nVert; i++)
fprintf(obj_file, "v %f %f %f\n", vertices[i].x,
vertices[i].y, vertices[i].z);
}
/* export the face normals */
for (i = 0; i < nFaces; i++){
/* calculate cross product between v1-v0 and v2-v0 */
v1 = vertices[faces[i*3+1]];
v2 = vertices[faces[i*3+2]];
v1.x -= vertices[faces[i*3]].x;
v1.y -= vertices[faces[i*3]].y;
v1.z -= vertices[faces[i*3]].z;
v2.x -= vertices[faces[i*3]].x;
v2.y -= vertices[faces[i*3]].y;
v2.z -= vertices[faces[i*3]].z;
normal = cross(&v1, &v2);
/* normalise to unit length */
scale = 1.0/(sqrt(pow(normal.x, 2.0)+pow(normal.y, 2.0)+pow(normal.z, 2.0))+2.23e-9);
normal.x *= scale;
normal.y *= scale;
normal.z *= scale;
fprintf(obj_file, "vn %f %f %f\n", normal.x, normal.y, normal.z);
}
/* export the face indices */
if(keepOnlyUsedVerticesFLAG){
for (i = 0; i < nFaces; i++){
/* vertices are in same order as the faces, and normals are in order */
fprintf(obj_file, "f %u//%u %u//%u %u//%u\n",
i*3 + 1, i + 1,
i*3+1 + 1, i + 1,
i*3+2 + 1, i + 1);
}
}
else {
/* just normals are in order */
for (i = 0; i < nFaces; i++){
fprintf(obj_file, "f %u//%u %u//%u %u//%u\n",
faces[i*3] + 1, i + 1,
faces[i*3+1] + 1, i + 1,
faces[i*3+2] + 1, i + 1);
}
}
fclose(obj_file);
}
void convhull_3d_export_m
(
ch_vertex* const vertices,
const int nVert,
int* const faces,
const int nFaces,
char* const m_filename
)
{
int i;
char path[256] = { "\0" };
memcpy(path, m_filename, strlen(m_filename));
FILE* m_file;
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
CV_STRCAT(path, ".m");
fopen_s(&m_file, path, "wt");
#else
m_file = fopen(strcat(path, ".m"), "wt");
#endif
/* save face indices and vertices for verification in matlab: */
fprintf(m_file, "vertices = [\n");
for (i = 0; i < nVert; i++)
fprintf(m_file, "%f, %f, %f;\n", vertices[i].x, vertices[i].y, vertices[i].z);
fprintf(m_file, "];\n\n\n");
fprintf(m_file, "faces = [\n");
for (int i = 0; i < nFaces; i++) {
fprintf(m_file, " %u, %u, %u;\n",
faces[3*i+0]+1,
faces[3*i+1]+1,
faces[3*i+2]+1);
}
fprintf(m_file, "];\n\n\n");
fclose(m_file);
}
void extractVerticesFromObjFile(char* const obj_filename, ch_vertex** out_vertices, int* out_nVert)
{
FILE* obj_file;
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
CV_STRCAT(obj_filename, ".obj");
fopen_s(&obj_file, obj_filename, "r");
#else
obj_file = fopen(strcat(obj_filename, ".obj"), "r");
#endif
/* determine number of vertices */
unsigned int nVert = 0;
char line[256];
while (fgets(line, sizeof(line), obj_file)) {
char* vexists = strstr(line, "v ");
if(vexists!=NULL)
nVert++;
}
(*out_nVert) = nVert;
(*out_vertices) = (ch_vertex*)malloc(nVert*sizeof(ch_vertex));
/* extract the vertices */
rewind(obj_file);
int i=0;
int vertID, prev_char_isDigit, current_char_isDigit;
char vert_char[256] = { 0 };
while (fgets(line, sizeof(line), obj_file)) {
char* vexists = strstr(line, "v ");
if(vexists!=NULL){
prev_char_isDigit = 0;
vertID = -1;
for(int j=0; j<strlen(line)-1; j++){
if(isdigit(line[j])||line[j]=='.'||line[j]=='-'||line[j]=='+'||line[j]=='E'||line[j]=='e'){
vert_char[strlen(vert_char)] = line[j];
current_char_isDigit = 1;
}
else
current_char_isDigit = 0;
if((prev_char_isDigit && !current_char_isDigit) || j ==strlen(line)-2 ){
vertID++;
if(vertID>4){
/* not a valid file */
free((*out_vertices));
(*out_vertices) = NULL;
(*out_nVert) = 0;
return;
}
(*out_vertices)[i].v[vertID] = atof(vert_char);
memset(vert_char, 0, 256 * sizeof(char));
}
prev_char_isDigit = current_char_isDigit;
}
i++;
}
}
}
#endif /* CONVHULL_3D_ENABLE */

View File

@ -1012,6 +1012,9 @@ public:
std::size_t size() const { std::size_t size() const {
return m_vertices.size(); return m_vertices.size();
} }
const Vector3& operator[]( std::size_t i ) const {
return m_vertices[i];
}
brushsplit_t classify_plane( const Plane3& plane ) const { brushsplit_t classify_plane( const Plane3& plane ) const {
brushsplit_t split; brushsplit_t split;
for( const_iterator i = begin(); i != end(); ++i ){ for( const_iterator i = begin(); i != end(); ++i ){
@ -1084,6 +1087,53 @@ public:
} }
}; };
#include "convhull_3d.h"
void CSG_build_hull( const MergeVertices& mergeVertices, MergePlanes& mergePlanes ){
#if 0
/* bruteforce new planes */
for( MergeVertices::const_iterator i = mergeVertices.begin() + 0; i != mergeVertices.end() - 2; ++i )
for( MergeVertices::const_iterator j = i + 1; j != mergeVertices.end() - 1; ++j )
for( MergeVertices::const_iterator k = j + 1; k != mergeVertices.end() - 0; ++k ){
const Plane3 plane = plane3_for_points( *i, *j, *k );
if( plane3_valid( plane ) ){
const brushsplit_t split = mergeVertices.classify_plane( plane );
if( ( split.counts[ePlaneFront] == 0 ) != ( split.counts[ePlaneBack] == 0 ) ){
if( split.counts[ePlaneFront] != 0 )
mergePlanes.insert( MergePlane( plane3_flipped( plane ), *i, *j, *k ) );
else
mergePlanes.insert( MergePlane( plane, *i, *k, *j ) );
}
}
}
#else
const int nVertices = mergeVertices.size();
ch_vertex* vertices = ( ch_vertex* )malloc( mergeVertices.size() * sizeof( ch_vertex ) );
for( std::size_t i = 0; i < mergeVertices.size(); ++i ){
vertices[i].x = static_cast<double>( mergeVertices[i].x() );
vertices[i].y = static_cast<double>( mergeVertices[i].y() );
vertices[i].z = static_cast<double>( mergeVertices[i].z() );
}
int* faceIndices = NULL;
int nFaces;
convhull_3d_build( vertices, nVertices, &faceIndices, &nFaces );
/* Where 'faceIndices' is a flat 2D matrix [nFaces x 3] */
for( int i = 0; i < nFaces; ++i ){
Vector3 p[3];
for( int j = 0; j < 3; ++j ){
// p[j] = Vector3( vertices[faceIndices[i * 3 + j]].x, vertices[faceIndices[i * 3 + j]].y, vertices[faceIndices[i * 3 + j]].z );
p[j] = mergeVertices[faceIndices[i * 3 + j]];
}
const Plane3 plane = plane3_for_points( p[0], p[1], p[2] );
if( plane3_valid( plane ) ){
mergePlanes.insert( MergePlane( plane, p[0], p[2], p[1] ) );
}
}
free( vertices );
free( faceIndices );
#endif
}
void CSG_WrapMerge( const ClipperPoints& clipperPoints ){ void CSG_WrapMerge( const ClipperPoints& clipperPoints ){
const bool primit = ( GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive ); const bool primit = ( GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive );
brush_vector_t selected_brushes; brush_vector_t selected_brushes;
@ -1127,21 +1177,8 @@ void CSG_WrapMerge( const ClipperPoints& clipperPoints ){
mergePlanes.insert( MergePlane( face.getPlane().plane3(), &face ) ); mergePlanes.insert( MergePlane( face.getPlane().plane3(), &face ) );
} }
} }
/* bruteforce new planes */
for( MergeVertices::const_iterator i = mergeVertices.begin() + 0; i != mergeVertices.end() - 2; ++i ) CSG_build_hull( mergeVertices, mergePlanes );
for( MergeVertices::const_iterator j = i + 1; j != mergeVertices.end() - 1; ++j )
for( MergeVertices::const_iterator k = j + 1; k != mergeVertices.end() - 0; ++k ){
const Plane3 plane = plane3_for_points( *i, *j, *k );
if( plane3_valid( plane ) ){
const brushsplit_t split = mergeVertices.classify_plane( plane );
if( ( split.counts[ePlaneFront] == 0 ) != ( split.counts[ePlaneBack] == 0 ) ){
if( split.counts[ePlaneFront] != 0 )
mergePlanes.insert( MergePlane( plane3_flipped( plane ), *i, *j, *k ) );
else
mergePlanes.insert( MergePlane( plane, *i, *k, *j ) );
}
}
}
//globalOutputStream() << mergePlanes.size() << " mergePlanes.size()\n"; //globalOutputStream() << mergePlanes.size() << " mergePlanes.size()\n";
if( mergePlanes.size() < 4 ){ if( mergePlanes.size() < 4 ){
@ -1242,21 +1279,8 @@ void CSG_DeleteComponents(){
} }
} }
/* bruteforce new planes */ CSG_build_hull( mergeVertices, mergePlanes );
for( MergeVertices::const_iterator i = mergeVertices.begin() + 0; i != mergeVertices.end() - 2; ++i )
for( MergeVertices::const_iterator j = i + 1; j != mergeVertices.end() - 1; ++j )
for( MergeVertices::const_iterator k = j + 1; k != mergeVertices.end() - 0; ++k ){
const Plane3 plane = plane3_for_points( *i, *j, *k );
if( plane3_valid( plane ) ){
const brushsplit_t split = mergeVertices.classify_plane( plane );
if( ( split.counts[ePlaneFront] == 0 ) != ( split.counts[ePlaneBack] == 0 ) ){
if( split.counts[ePlaneFront] != 0 )
mergePlanes.insert( MergePlane( plane3_flipped( plane ), *i, *j, *k ) );
else
mergePlanes.insert( MergePlane( plane, *i, *k, *j ) );
}
}
}
if( mergePlanes.size() < 4 ){ if( mergePlanes.size() < 4 ){
globalWarningStream() << "CSG_DeleteComponents: Too few planes left: " << mergePlanes.size() << ".\n"; globalWarningStream() << "CSG_DeleteComponents: Too few planes left: " << mergePlanes.size() << ".\n";
return; return;