I have a question about use SUGeometryInputRef

Copy all faces of test_src.skp to test_dest.skp.
Some faces can’t be constructed, and I can’t make the face by hand.

test_src.skp (15.6 KB) test_dest.skp (14.7 KB)

image image

#include<SketchUpAPI\sketchup.h>
#include<stdio.h>
#include<vector>
#include<assert.h>

#define SU(api_function_call) {\
  SUResult su_api_result = api_function_call;\
  assert(SU_ERROR_NONE == su_api_result);\
}\

// Add all face of the src_entities to geom_input
// [in] src_entities
// [in] geom_input
// [out] vertex_index   next index of vertex to be added in geom_input
bool AddFaces(SUEntitiesRef src_entities, SUGeometryInputRef geom_input, size_t *vertex_index);

// Add vertices of loop to geom_input, and record index of vertex in input_loop
// [in] geom_input
// [in] loop
// [in] input_loop
// [out] vertex_index   next index of vertex to be added in geom_input
void HandleLoop(SUGeometryInputRef geom_input, SULoopRef loop, SULoopInputRef input_loop, size_t *vertex_index);


int main() {
	SUInitialize();
	SUModelRef src_model = SU_INVALID,dest_model= SU_INVALID;
	SUModelLoadStatus loadStatus;

    // get the model from test_src.skp  =>  src_model
	SU(SUModelCreateFromFileWithStatus(&src_model, "test_src.skp", &loadStatus));

    // Create a empty model  =>  dest_model
	SUModelCreate(&dest_model);

	SUEntitiesRef src_entities = SU_INVALID,dest_entities = SU_INVALID;

    // get the entities of the src_model
	SU(SUModelGetEntities(src_model, &src_entities));

    // get the entities of the dest_model
	SU(SUModelGetEntities(dest_model, &dest_entities));

	SUGeometryInputRef geom_input = SU_INVALID;
	SU(SUGeometryInputCreate(&geom_input));

	size_t vertex_index = 0;
    // Add all face of the src_entities to geom_input
	bool flag = AddFaces(src_entities, geom_input, &vertex_index);

    // Fill geom_input into dest_entities
	if (flag) SU(SUEntitiesFill(dest_entities, geom_input, true));
	SU(SUGeometryInputRelease(&geom_input));

    // save dest_model to test_dest.skp
	SU(SUModelSaveToFile(dest_model, "test_dest.skp"));

	SU(SUModelRelease(&src_model));
	SU(SUModelRelease(&dest_model));
	SUTerminate();
	return 0;
}

bool AddFaces(SUEntitiesRef src_entities, SUGeometryInputRef geom_input, size_t * vertex_index)
{
	size_t num = 0;
    // get the number of faces in the src_entities. 
	SU(SUEntitiesGetNumFaces(src_entities, &num));

    // no faces
	if (num <= 0) return false;

    
	std::vector<SUFaceRef> src_faces(num);
    // get all faces in the src_entities. 
	SU(SUEntitiesGetFaces(src_entities, num, &src_faces[0], &num));

	for (int i = 0; i < num; i++) {
        // add the src_face to geom_input

		SUFaceRef src_face = src_faces[i];
		SULoopRef out_loop = SU_INVALID;

        // get out_loop of the src_face
		SU(SUFaceGetOuterLoop(src_face, &out_loop));

		SULoopInputRef outer_input_loop = SU_INVALID;
		SU(SULoopInputCreate(&outer_input_loop));

        // Add vertices of out_loop to geom_input, and record index of vertex in outer_input_loop
		HandleLoop(geom_input, out_loop, outer_input_loop, vertex_index);

		size_t added_face_index = -1;
        // Add outer_input_loop of src_face to geom_input
		SU(SUGeometryInputAddFace(geom_input, &outer_input_loop, &added_face_index));

		size_t inner_loops_length = 0;
        // get the number of inner_loops in the src_face
		SU(SUFaceGetNumInnerLoops(src_face, &inner_loops_length));
		if (inner_loops_length != 0) {
			std::vector<SULoopRef> inner_loops(inner_loops_length);

            // get all inner_loops in the src_face
			SU(SUFaceGetInnerLoops(src_face, inner_loops_length, &inner_loops[0], &inner_loops_length));
			for (int i = 0; i < inner_loops_length; i++) {

				SULoopInputRef inner_input_loop = SU_INVALID;
				SU(SULoopInputCreate(&inner_input_loop));
                
                // Add vertices of out_loop to geom_input, and record index of vertex in inner_input_loop
				HandleLoop(geom_input, out_loop, inner_input_loop, vertex_index);
                
                // Add inner_input_loop to geom_input
				SU(SUGeometryInputFaceAddInnerLoop(geom_input, added_face_index, &inner_input_loop));
			}
		}
	}
	return true;
}

void HandleLoop(SUGeometryInputRef geom_input, SULoopRef loop, SULoopInputRef input_loop, size_t * vertex_index)
{
	size_t vertex_num = 0;
    // get the number of vertices in the loop
	SU(SULoopGetNumVertices(loop, &vertex_num));
	if (vertex_num < 2) return;

	std::vector<SUVertexRef> loop_verts(vertex_num);
	std::vector<SUPoint3D> loop_pts;

    // get all vertices in the loop
	SU(SULoopGetVertices(loop, vertex_num, &loop_verts[0], &vertex_num));
	for (size_t i = 0; i < vertex_num; i++) {

		SUPoint3D pt;
		SU(SUVertexGetPosition(loop_verts[i], &pt));
        // add vertex to geom_input
		SU(SUGeometryInputAddVertex(geom_input, &pt));
        
        // record index of vertex in loop
		SU(SULoopInputAddVertexIndex(input_loop, (*vertex_index) + i));
		loop_pts.push_back(pt);
	}
	(*vertex_index) += vertex_num;
}

Please edit your original post and be more descriptive:

  • What are you trying to achieve ?
  • What do you expect for a result ?
  • What is happening or not happening ?

P.S. - I saw only 2 very small code comments in your C code. It is recommended to comment your code better than this, especially if you want other coders to understand what the code does.

1 Like

@DanRathbun

I will fill in the notes.

I copy the face of the_src.skp to test_dest.skp with SketchUp C API.

There’s a face missing in the test_dest.skp.

And the face cannot be filled with SketchUp.
I have to delete a border and redraw it in SketchUp.

Does any of the function calls fail at any point?

No, the results returned by all methods are judged by assertions.

Had a quick look via the debugger. When the face with an inner hole is added the inner loop passed contains 3 vertices. And there are four faces being created. When you open the model you get four faces.
But when you select any of the edges of the missing triable there are unexpected results in the faces they connect to:

It looks like the loop for the inner loop is actually the outer loop. That explains why the boundary edges for the missing triangle return a face twice.

I haven’t had time to dig into the source of the issue, but it looks like you’re passing in the wrong loop index.

1 Like

Thank you, I find the bug. I should use the inner_loops[j], or not out_loop, and the for loop variable I have also repeated above.

So stupid!

size_t inner_loops_length = 0;
SU(SUFaceGetNumInnerLoops(src_face, &inner_loops_length));
if (inner_loops_length != 0) {
    std::vector<SULoopRef> inner_loops(inner_loops_length);
    SU(SUFaceGetInnerLoops(src_face, inner_loops_length, &inner_loops[0], &inner_loops_length));
    // for (int i = 0; i < inner_loops_length; i++) {
    for (int j = 0; j < inner_loops_length; j++) {
        SULoopInputRef inner_input_loop = SU_INVALID;
        SU(SULoopInputCreate(&inner_input_loop));
        // HandleLoop(geom_input, out_loop, inner_input_loop, vertex_index);
        HandleLoop(geom_input, inner_loops[j], inner_input_loop, vertex_index);
        SU(SUGeometryInputFaceAddInnerLoop(geom_input, added_face_index, &inner_input_loop));
    }
}
1 Like

I should have carefully examined your words. I was impetuous