use convhull_3d for quicker hull calculation
This commit is contained in:
parent
1191f54ef4
commit
736f89026f
|
|
@ -1,16 +1,16 @@
|
|||
/*
|
||||
Copyright (c) 2017-2018 Leo McCormack
|
||||
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
|
|
@ -57,7 +57,7 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef CONVHULL_3D_USE_FLOAT_PRECISION
|
||||
typedef float CH_FLOAT;
|
||||
#else
|
||||
|
|
@ -72,7 +72,7 @@ typedef struct _ch_vertex {
|
|||
};
|
||||
} ch_vertex;
|
||||
typedef ch_vertex ch_vec3;
|
||||
|
||||
|
||||
/* builds the convexhull, returning the face indices corresponding to "in_vertices" */
|
||||
void convhull_3d_build(/* input arguments */
|
||||
ch_vertex* const in_vertices, /* vector of input vertices; nVert x 1 */
|
||||
|
|
@ -80,30 +80,6 @@ void convhull_3d_build(/* input arguments */
|
|||
/* output arguments */
|
||||
int** out_faces, /* & of empty int*, output face indices; flat: nOut_faces x 3 */
|
||||
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
|
||||
} /*extern "C"*/
|
||||
|
|
@ -116,22 +92,11 @@ void extractVerticesFromObjFile(/* input arguments */
|
|||
* INTERNAL:
|
||||
***********/
|
||||
|
||||
#ifdef CONVHULL_3D_ENABLE
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <float.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
|
||||
#define CH_FLT_MIN FLT_MIN
|
||||
#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 void sort_float(CH_FLOAT*, CH_FLOAT*, 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 void plane_3d(CH_FLOAT*, CH_FLOAT*, CH_FLOAT*);
|
||||
static void ismember(int*, int*, int*, int, int);
|
||||
|
||||
/* internal functions definitions: */
|
||||
static int cmp_asc_float(const void *a,const void *b) {
|
||||
struct float_w_idx *a1 = (struct float_w_idx*)a;
|
||||
struct float_w_idx *a2 = (struct float_w_idx*)b;
|
||||
const struct float_w_idx *a1 = (const struct float_w_idx*)a;
|
||||
const struct float_w_idx *a2 = (const struct float_w_idx*)b;
|
||||
if((*a1).val<(*a2).val)return -1;
|
||||
else if((*a1).val>(*a2).val)return 1;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
static int cmp_desc_float(const void *a,const void *b) {
|
||||
struct float_w_idx *a1 = (struct float_w_idx*)a;
|
||||
struct float_w_idx *a2 = (struct float_w_idx*)b;
|
||||
const struct float_w_idx *a1 = (const struct float_w_idx*)a;
|
||||
const struct float_w_idx *a2 = (const struct float_w_idx*)b;
|
||||
if((*a1).val>(*a2).val)return -1;
|
||||
else if((*a1).val<(*a2).val)return 1;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
static int cmp_asc_int(const void *a,const void *b) {
|
||||
struct int_w_idx *a1 = (struct int_w_idx*)a;
|
||||
struct int_w_idx *a2 = (struct int_w_idx*)b;
|
||||
const struct int_w_idx *a1 = (const struct int_w_idx*)a;
|
||||
const struct int_w_idx *a2 = (const struct int_w_idx*)b;
|
||||
if((*a1).val<(*a2).val)return -1;
|
||||
else if((*a1).val>(*a2).val)return 1;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
static int cmp_desc_int(const void *a,const void *b) {
|
||||
struct int_w_idx *a1 = (struct int_w_idx*)a;
|
||||
struct int_w_idx *a2 = (struct int_w_idx*)b;
|
||||
const struct int_w_idx *a1 = (const struct int_w_idx*)a;
|
||||
const struct int_w_idx *a2 = (const struct int_w_idx*)b;
|
||||
if((*a1).val>(*a2).val)return -1;
|
||||
else if((*a1).val<(*a2).val)return 1;
|
||||
else return 0;
|
||||
|
|
@ -216,7 +180,7 @@ static void sort_float
|
|||
{
|
||||
int i;
|
||||
struct float_w_idx *data;
|
||||
|
||||
|
||||
data = (float_w_idx*)malloc(len*sizeof(float_w_idx));
|
||||
for(i=0;i<len;i++) {
|
||||
data[i].val=in_vec[i];
|
||||
|
|
@ -248,7 +212,7 @@ static void sort_int
|
|||
{
|
||||
int i;
|
||||
struct int_w_idx *data;
|
||||
|
||||
|
||||
data = (int_w_idx*)malloc(len*sizeof(int_w_idx));
|
||||
for(i=0;i<len;i++) {
|
||||
data[i].val=in_vec[i];
|
||||
|
|
@ -269,15 +233,6 @@ static void sort_int
|
|||
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 */
|
||||
static CH_FLOAT det_4x4(CH_FLOAT* m) {
|
||||
return
|
||||
|
|
@ -310,7 +265,7 @@ static void plane_3d
|
|||
int r[3];
|
||||
CH_FLOAT sign, det, norm_c;
|
||||
CH_FLOAT pdiff[2][3], pdiff_s[2][2];
|
||||
|
||||
|
||||
for(i=0; i<2; i++)
|
||||
for(j=0; j<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;
|
||||
CH_FLOAT dfi, v, max_p, min_p;
|
||||
CH_FLOAT* points, *cf, *cfi, *df, *p_s, *span;
|
||||
|
||||
|
||||
if(nVert<3 || in_vertices==NULL){
|
||||
(*out_faces) = NULL;
|
||||
(*nOut_faces) = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* 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 */
|
||||
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)+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 */
|
||||
nFaces = (d+1);
|
||||
faces = (int*)calloc(nFaces*d, sizeof(int));
|
||||
aVec = (int*)malloc(nFaces*sizeof(int));
|
||||
for(i=0; i<nFaces; i++)
|
||||
aVec[i] = i;
|
||||
|
||||
|
||||
/* Each column of cf contains the coefficients of a plane */
|
||||
cf = (CH_FLOAT*)malloc(nFaces*d*sizeof(CH_FLOAT));
|
||||
cfi = (CH_FLOAT*)malloc(d*sizeof(CH_FLOAT));
|
||||
|
|
@ -426,12 +381,12 @@ void convhull_3d_build
|
|||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Calculate and store the plane coefficients of the face */
|
||||
for(j=0; j<d; j++)
|
||||
for(k=0; k<d; k++)
|
||||
p_s[j*d+k] = points[(faces[i*d+j])*(d+1) + k];
|
||||
|
||||
|
||||
/* Calculate and store the plane coefficients of the face */
|
||||
plane_3d(p_s, cfi, &dfi);
|
||||
for(j=0; j<d; j++)
|
||||
|
|
@ -440,12 +395,12 @@ void convhull_3d_build
|
|||
}
|
||||
CH_FLOAT *A;
|
||||
int *bVec, *fVec, *asfVec, *face_tmp;
|
||||
|
||||
|
||||
/* Check to make sure that faces are correctly oriented */
|
||||
bVec = (int*)malloc(4*sizeof(int));
|
||||
for(i=0; i<d+1; i++)
|
||||
bVec[i] = i;
|
||||
|
||||
|
||||
/* A contains the coordinates of the points forming a simplex */
|
||||
A = (CH_FLOAT*)calloc((d+1)*(d+1), sizeof(CH_FLOAT));
|
||||
face_tmp = (int*)malloc((d+1)*sizeof(int));
|
||||
|
|
@ -463,10 +418,10 @@ void convhull_3d_build
|
|||
for(; i<(d+1); i++)
|
||||
for(j=0; j<(d+1); j++)
|
||||
A[i*(d+1)+j] = points[p*(d+1)+j];
|
||||
|
||||
|
||||
/* det(A) determines the orientation of the face */
|
||||
v = det_4x4(A);
|
||||
|
||||
|
||||
/* Orient so that each point on the original simplex can't see the opposite face */
|
||||
if(v<0){
|
||||
/* 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];
|
||||
for(j=0, l=d-2; j<d-1; j++, l++)
|
||||
faces[k*d+l] = face_tmp[d-j-1];
|
||||
|
||||
|
||||
/* Modify the plane coefficients of the properly oriented faces */
|
||||
for(j=0; j<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];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Coordinates of the center of the point set */
|
||||
CH_FLOAT* meanp, *absdist, *reldist, *desReldist;
|
||||
meanp = (CH_FLOAT*)calloc(d, sizeof(CH_FLOAT));
|
||||
|
|
@ -496,41 +451,41 @@ void convhull_3d_build
|
|||
meanp[j] += points[i*(d+1)+j];
|
||||
for(j=0; j<d; j++)
|
||||
meanp[j] = meanp[j]/(CH_FLOAT)(nVert-d-1);
|
||||
|
||||
|
||||
/* Absolute distance of points from the center */
|
||||
absdist = (CH_FLOAT*)malloc((nVert-d-1)*d * sizeof(CH_FLOAT));
|
||||
for(i=d+1, k=0; i<nVert; i++, k++)
|
||||
for(j=0; j<d; j++)
|
||||
absdist[k*d+j] = (points[i*(d+1)+j] - meanp[j])/span[j];
|
||||
|
||||
|
||||
/* Relative distance of points from the center */
|
||||
reldist = (CH_FLOAT*)calloc((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(j=0; j<d; j++)
|
||||
reldist[i] += pow(absdist[i*d+j], 2.0);
|
||||
|
||||
|
||||
/* Sort from maximum to minimum relative distance */
|
||||
int num_pleft, cnt;
|
||||
int* ind, *pleft;
|
||||
ind = (int*)malloc((nVert-d-1) * sizeof(int));
|
||||
pleft = (int*)malloc((nVert-d-1) * sizeof(int));
|
||||
sort_float(reldist, desReldist, ind, (nVert-d-1), 1);
|
||||
|
||||
|
||||
/* Initialize the vector of points left. The points with the larger relative
|
||||
distance from the center are scanned first. */
|
||||
num_pleft = (nVert-d-1);
|
||||
for(i=0; i<num_pleft; i++)
|
||||
pleft[i] = ind[i]+d+1;
|
||||
|
||||
|
||||
/* Loop over all remaining points that are not deleted. Deletion of points
|
||||
occurs every #iter2del# iterations of this while loop */
|
||||
memset(A, 0, (d+1)*(d+1) * sizeof(CH_FLOAT));
|
||||
|
||||
|
||||
/* cnt is equal to the points having been selected without deletion of
|
||||
nonvisible points (i.e. points inside the current convex hull) */
|
||||
cnt=0;
|
||||
|
||||
|
||||
/* The main loop for the quickhull algorithm */
|
||||
CH_FLOAT detA;
|
||||
CH_FLOAT* points_cf, *points_s;
|
||||
|
|
@ -549,7 +504,7 @@ void convhull_3d_build
|
|||
while( (num_pleft>0) ){
|
||||
/* i is the first point of the points left */
|
||||
i = pleft[0];
|
||||
|
||||
|
||||
/* Delete the point selected */
|
||||
for(j=0; j<num_pleft-1; j++)
|
||||
pleft[j] = pleft[j+1];
|
||||
|
|
@ -558,10 +513,10 @@ void convhull_3d_build
|
|||
free(pleft);
|
||||
else
|
||||
pleft = (int*)realloc(pleft, num_pleft*sizeof(int));
|
||||
|
||||
|
||||
/* Update point selection counter */
|
||||
cnt++;
|
||||
|
||||
|
||||
/* find visible faces */
|
||||
for(j=0; j<d; j++)
|
||||
points_s[j] = points[i*(d+1)+j];
|
||||
|
|
@ -596,7 +551,7 @@ void convhull_3d_build
|
|||
visible_ind[j] = 0;
|
||||
}
|
||||
num_nonvisible_faces = nFaces - num_visible_ind;
|
||||
|
||||
|
||||
/* proceed if there are any visible faces */
|
||||
if(num_visible_ind!=0){
|
||||
/* Find visible face indices */
|
||||
|
|
@ -607,7 +562,7 @@ void convhull_3d_build
|
|||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Find nonvisible faces */
|
||||
nonvisible_faces = (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++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Create horizon (count is the number of the edges of the horizon) */
|
||||
count=0;
|
||||
for(j=0; j<num_visible_ind; j++){
|
||||
|
|
@ -629,7 +584,7 @@ void convhull_3d_build
|
|||
sort_int(face_s, NULL, NULL, d, 0);
|
||||
ismember(nonvisible_faces, face_s, f0, num_nonvisible_faces*d, d);
|
||||
u_len = 0;
|
||||
|
||||
|
||||
/* u are the nonvisible faces connected to the face v, if any */
|
||||
for(k=0; k<num_nonvisible_faces; k++){
|
||||
f0_sum = 0;
|
||||
|
|
@ -669,7 +624,7 @@ void convhull_3d_build
|
|||
/* Delete visible faces */
|
||||
for(k=0; k<d; k++)
|
||||
faces[l*d+k] = faces[j*d+k];
|
||||
|
||||
|
||||
/* Delete the corresponding plane coefficients of the faces */
|
||||
for(k=0; k<d; k++)
|
||||
cf[l*d+k] = cf[j*d+k];
|
||||
|
|
@ -677,16 +632,16 @@ void convhull_3d_build
|
|||
l++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Update the number of faces */
|
||||
nFaces = nFaces-num_visible_ind;
|
||||
faces = (int*)realloc(faces, nFaces*d*sizeof(int));
|
||||
cf = (CH_FLOAT*)realloc(cf, nFaces*d*sizeof(CH_FLOAT));
|
||||
df = (CH_FLOAT*)realloc(df, nFaces*sizeof(CH_FLOAT));
|
||||
|
||||
|
||||
/* start is the first row of the new faces */
|
||||
start=nFaces;
|
||||
|
||||
|
||||
/* Add faces connecting horizon to the new point */
|
||||
n_newfaces = horizon_size1;
|
||||
for(j=0; j<n_newfaces; j++){
|
||||
|
|
@ -697,7 +652,7 @@ void convhull_3d_build
|
|||
for(k=0; k<d-1; k++)
|
||||
faces[(nFaces-1)*d+k] = horizon[j*(d-1)+k];
|
||||
faces[(nFaces-1)*d+(d-1)] = i;
|
||||
|
||||
|
||||
/* Calculate and store appropriately the plane coefficients of the faces */
|
||||
for(k=0; k<d; k++)
|
||||
for(l=0; l<d; l++)
|
||||
|
|
@ -712,7 +667,7 @@ void convhull_3d_build
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Orient each new face properly */
|
||||
hVec = (int*)malloc( nFaces*sizeof(int));
|
||||
hVec_mem_face = (int*)malloc( nFaces*sizeof(int));
|
||||
|
|
@ -736,7 +691,7 @@ void convhull_3d_build
|
|||
}
|
||||
index = 0;
|
||||
detA = 0.0;
|
||||
|
||||
|
||||
/* While new point is coplanar, choose another point */
|
||||
while(detA==0.0){
|
||||
for(j=0;j<d; j++)
|
||||
|
|
@ -748,7 +703,7 @@ void convhull_3d_build
|
|||
index++;
|
||||
detA = det_4x4(A);
|
||||
}
|
||||
|
||||
|
||||
/* Orient faces so that each point on the original simplex can't see the opposite face */
|
||||
if (detA<0.0){
|
||||
/* 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];
|
||||
for(j=0, l=d-2; j<d-1; j++, l++)
|
||||
faces[k*d+l] = face_tmp[d-j-1];
|
||||
|
||||
|
||||
/* Modify the plane coefficients of the properly oriented faces */
|
||||
for(j=0; j<d; j++)
|
||||
cf[k*d+j] = -cf[k*d+j];
|
||||
|
|
@ -781,7 +736,7 @@ void convhull_3d_build
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* output */
|
||||
if(FUCKED){
|
||||
(*out_faces) = NULL;
|
||||
|
|
@ -792,7 +747,7 @@ void convhull_3d_build
|
|||
memcpy((*out_faces),faces, nFaces*d*sizeof(int));
|
||||
(*nOut_faces) = nFaces;
|
||||
}
|
||||
|
||||
|
||||
/* clean-up */
|
||||
free(visible_ind);
|
||||
free(points_cf);
|
||||
|
|
@ -819,178 +774,5 @@ void convhull_3d_build
|
|||
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 */
|
||||
|
|
|
|||
|
|
@ -1012,6 +1012,9 @@ public:
|
|||
std::size_t size() const {
|
||||
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 split;
|
||||
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 ){
|
||||
const bool primit = ( GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive );
|
||||
brush_vector_t selected_brushes;
|
||||
|
|
@ -1127,21 +1177,8 @@ void CSG_WrapMerge( const ClipperPoints& clipperPoints ){
|
|||
mergePlanes.insert( MergePlane( face.getPlane().plane3(), &face ) );
|
||||
}
|
||||
}
|
||||
/* 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 ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CSG_build_hull( mergeVertices, mergePlanes );
|
||||
|
||||
//globalOutputStream() << mergePlanes.size() << " mergePlanes.size()\n";
|
||||
if( mergePlanes.size() < 4 ){
|
||||
|
|
@ -1242,21 +1279,8 @@ void CSG_DeleteComponents(){
|
|||
}
|
||||
}
|
||||
|
||||
/* 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 ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
CSG_build_hull( mergeVertices, mergePlanes );
|
||||
|
||||
if( mergePlanes.size() < 4 ){
|
||||
globalWarningStream() << "CSG_DeleteComponents: Too few planes left: " << mergePlanes.size() << ".\n";
|
||||
return;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user