use convhull_3d for quicker hull calculation
This commit is contained in:
parent
1191f54ef4
commit
736f89026f
|
|
@ -81,30 +81,6 @@ void convhull_3d_build(/* input 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"*/
|
||||
#endif
|
||||
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
|
|
@ -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