SUEntitiesFill and/or SUGeometryInputAddFace size limit?


#1

Hi all,

I am new to the new Sketchup SDK and I am currently trying to migrate an old converter. It works fairly well (the new SDK is much better documented than the old one :slight_smile: ) except for one point.

I use a geometry input to create my faces, since they are textured faces and so I need to set the texture coordinates. And at the end I use the SUEntitiesFill.

When trying to convert an object that has 4700 faces, I ended up with an empty SketchUp database. After some debugging, I realised that if I limited the number of faces to 2000 faces, it worked OK. So I thought there was a size limitation and tried to do the SUEntitiesFill every 2000 faces, reset the geometry input and go on. But it does not seem to work that way…

So my questions are : is there a size limit to the SUEntitiesFill or to the geometry input ? and how can I do what I want ? (without creating a serie of child components with 2000 faces :wink: )

I would really appreciate help :slight_smile:

Thanks a lot and have a good day

Here is the code loop I currently use:

    SUGeometryInputRef skpGeomInput;
    SUSetInvalid(skpGeomInput);
    SUGeometryInputCreate(&skpGeomInput);
    
    // we store the SKP vertex index
    int skpVtxIndex = 0;
    size_t skpFaceIndex = 0;
    int realNbFace = 0;
    
    // browsing through the object faces
    for(INDICE_SDM iface = MBOIsetNext(object.face, -1); iface != -1; iface = MBOIsetNext(object.face, iface))
    {
        if(skpFaceIndex > 2000)
        {
            // we flush the already converted faces
            SUEntitiesFill(container, skpGeomInput, false);
            // we release the geometry input
            SUGeometryInputRelease(&skpGeomInput);
            // we create a new one
            SUSetInvalid(skpGeomInput);
            SUGeometryInputCreate(&skpGeomInput);
            // we reset the indices
            skpVtxIndex = 0;
            skpFaceIndex = 0;
        }
        
        Sdm3dLireAspectFace(sdmdb, iobj, iface, &aspectFaceComplet);
        
        const poly & face = object.face[iface];
        
        // getting the face vertices coordinates and adding it to a loop
        int ivtx, nbVertex = MBOIlisteLength(face.ind_sommet);
        SULoopInputRef skpFaceLoop;
        SUSetInvalid(skpFaceLoop);
        SULoopInputCreate(&skpFaceLoop);
        for(ivtx = 0; ivtx < nbVertex; ivtx++)
        {
            som vertexPosition;
            INDICE_SDM rep = SdmRepereCourant(sdmdb, iobj);
            SdmRepereLireSommet(sdmdb, iobj, face.ind_sommet[ivtx], rep, &vertexPosition);
            
            SUPoint3D skpVtx;
            skpVtx.x = vertexPosition.x*METER_TO_INCH; //
            skpVtx.y = vertexPosition.y*METER_TO_INCH; // Conversion from meters to inch
            skpVtx.z = vertexPosition.z*METER_TO_INCH; //
            
            if(ivtx < 4) // the material input structure only wants 4 vertices to define the texturing
                skpFaceVtxIndices[ivtx] = skpVtxIndex;
            
            SUGeometryInputAddVertex(skpGeomInput, &skpVtx);
            SULoopInputAddVertexIndex(skpFaceLoop, skpVtxIndex);
            skpVtxIndex++;
        }
        
        SUGeometryInputAddFace(skpGeomInput, &skpFaceLoop, &skpFaceIndex);
        realNbFace++;
        
        // if we have to convert the materials, we set its aspect
        if(_convertMaterials)
            createFaceTextureAndColor(sdmdb, iobj, iface, sdmMat, sdmMot, aspectFaceComplet, skpFaceIndex, skpFaceVtxIndices, nbVertex, &skpGeomInput);
    }    
    
    SUEntitiesFill(container, skpGeomInput, false);
    size_t nbFace = -1;
    SUEntitiesGetNumFaces(container, &nbFace);
    printf("nbFace : %d realNbFace : %d", nbFace, realNbFace);
    
    SUGeometryInputRelease(&skpGeomInput);

#2

I do not know the answer to this, but am curious to find out. I have noticed in my code that in SK 2014 I get a crash when I am filling over 5000 faces. I do not get the crash in SK 2015.


#3

Thanks for the answer :smile:

Maybe the limitation was the solution for the crash ?

Does anybody have a clue on that ?

Thanks a lot


#4

There isn’t a size limit to any of the data structures. You are only limited by the available memory.
After a quick look at your code, I think your problem is that you keep adding vertices via SUGeometryInputAddVertex inside a face loop. So, vertices shared by neighboring faces would be added twice.

Normally, this wouldn’t be a problem since SUEntitiesFill would de-dupe the vertices by position. However, the vertex indices (that you specify with SULoopInputAddVertexIndex) will get out-of-sync. So I would suggest that you add all the vertices of the mesh first, and then specify each loop’s vertex indices by referencing these global vertices.


#5

Hi,

And thank you so much for your answer :smile: I’ll try that right away and let you know if it worked :smile:

Thanks a lot and have a good day.


#6

Hi again,

Bugra, I tried what you told me to do and… I have the same problem: it works perfect, except for my big object with 4700 faces that ends up with 0 faces in the geometry input… I copy the new code at the end of my message. The getObjectVertices function gets me all the vertices of an object.

What do I do wrong ?

Thanks again and have a good day.

        // we add all the object vertices to the geometry input
    SUPoint3D * objectVtx = new SUPoint3D[object.nb_sommet];
    getObjectVertices(sdmdb, iobj, object.nb_sommet, objectVtx);
    SUGeometryInputSetVertices(skpGeomInput, object.nb_sommet, objectVtx);
    
    // we store the SKP vertex index
    size_t skpFaceIndex = 0;
    
    // browsing through the object faces
    for(INDICE_SDM iface = MBOIsetNext(object.face, -1); iface != -1; iface = MBOIsetNext(object.face, iface))
    {
        /*if(_splitFaces && skpFaceIndex > SKP_MAX_FACE_NUMBER)
        {
            // we flush the already converted faces
            size_t nbFace = -1;
            SUEntitiesFill(curEntitiesRef, skpGeomInput, false);
            SUEntitiesGetNumFaces(curEntitiesRef, &nbFace);
            printf("object '%s': nbFace group %d : %d\n", object.nom_objet, nbGroup, nbFace);
            nbGroup++;
            // we release the geometry input
            SUGeometryInputRelease(&skpGeomInput);
            // we create a new group
            char groupName[256];
            sprintf(groupName, "face_group%d", nbGroup);
            curEntitiesRef = createGroupAndGetContainer(container, groupName);
            // we create a new one
            SUSetInvalid(skpGeomInput);
            SUGeometryInputCreate(&skpGeomInput);
            // we reset the indices
            skpFaceIndex = 0;
        }*/
        
        Sdm3dLireAspectFace(sdmdb, iobj, iface, &aspectFaceComplet);
        
        const poly & face = object.face[iface];
        
        // getting the face vertices coordinates and adding it to a loop
        int ivtx, nbVertex = MBOIlisteLength(face.ind_sommet);
        SULoopInputRef skpFaceLoop;
        SUSetInvalid(skpFaceLoop);
        SULoopInputCreate(&skpFaceLoop);
        for(ivtx = 0; ivtx < nbVertex; ivtx++)
        {
            int skpVtxIndex = face.ind_sommet[ivtx];
            if(ivtx < 4) // the material input structure only wants 4 vertices to define the texturing
                skpFaceVtxIndices[ivtx] = skpVtxIndex;
            SULoopInputAddVertexIndex(skpFaceLoop, skpVtxIndex);
        }
        
        SUGeometryInputAddFace(skpGeomInput, &skpFaceLoop, &skpFaceIndex);
        
        // if we have to convert the materials, we set its aspect
        if(_convertMaterials)
            createFaceTextureAndColor(sdmdb, iobj, iface, sdmMat, sdmMot, aspectFaceComplet, skpFaceIndex, skpFaceVtxIndices, nbVertex, &skpGeomInput);
    }    
    
    SUEntitiesFill(curEntitiesRef, skpGeomInput, false);
    size_t nbFace = -1;
    SUEntitiesGetNumFaces(curEntitiesRef, &nbFace);
    printf("object '%s': nbFace group %d : %d\n", object.nom_objet, nbGroup, nbFace);
    
    SUGeometryInputRelease(&skpGeomInput);
    
    delete [] objectVtx;

#7

Hi Carole,
Looking at your code, nothing is jumping out as wrong. However, I would suggest that you check the return values from every API call. They all return enum SUResult, which could give you a hint as to what is going wrong. I would particularly be interested in what SUEntitiesFill is returning in the case that fails.

If all else fails, I could debug it if you can duplicate the error in a small, buildable project. You can share it with me privately via a private message here.


#8

Thank you so much !

I’ll try that quickly and let you know if it works :smile:

Thanks again and have a good day.


#9

Hi again,

So I tried several things:

  • I tried to check the SULoopInputAddVertexIndex by adding some code:

              if(SULoopInputAddVertexIndex(skpFaceLoop, skpVtxIndex) != SU_ERROR_NONE)
                  printf("loop_input is not valid or vertex_index already exists in the loop\n");
    

If I do that and set a breakpoint on the “printf” line, it goes along correctly (by the way, it seems that there is an error in the documentation: the two error types of SU_CALL are the same).

  • I tried to check the SUGeometryInputAddFace by adding some code:

          if(SUGeometryInputAddFace(skpGeomInput, &skpFaceLoop, &skpFaceIndex) == SU_ERROR_NULL_POINTER_INPUT);
              printf("outer_loop is NULL\n");
    

If I do that and set a breakpoint on the “printf” line, it stops all the time but goes on creating faces. Then I used the “SU_CALL” macro instead of my test and no exception is thrown, it goes on pretty well.

  • then I tried to check SUEntitiesFill by adding some code:

      if(SUEntitiesFill(curEntitiesRef, skpGeomInput, false) == SU_ERROR_INVALID_INPUT)
      {
          if(SUIsInvalid(curEntitiesRef))
              printf("SUEntitiesFill: entities are invalid objects\n");
          if(SUIsInvalid(skpGeomInput))
              printf("SUEntitiesFill: geom input is an invalid object\n");
      }
    

Since the documentation says that if there is an error code the entities or geom_input are invalid objects, I checked them. So when I do that, I see that the error code is return but none of my reference is invalid… And if I try so replace all that by a SU_CALL, an exception is thrown but it does not tell me much…

Bugra, I checked with my boss and it’s OK to send you my programm in debug but the problem is we do not use MSDEV to compile it but our own makefile system. So I’m afraid that building an equivalent solution would be long and hazardous. Would the programm in debug, code and sample database would be OK ?

Once again, thank you so much for your help and have a good day.


#10

Thanks, I checked and I don’t think that’s an error. SU_ERROR_NULL_POINTER_INPUT is returned in both cases.

This is a bit contradicting. If it stops at the printf line, that means SU_ERROR_NULL_POINTER_INPUT is being returned. So SU_CALL should be throwing an exception too. So I don’t get that. But a null pointer input error indicates that you are passing null for outer_loop. That would be a problem.

Perhaps our documentation is unclear here but SU_ERROR_INVALID_INPUT doesn’t necessarily mean the reference itself is invalid. Our code will first check if the given geom_input describes a valid mesh. So it will validate everything you added into the geometry input object. For instance, if any one of the loop inputs contain less than 3 vertices, that will be considered invalid input. In this case, your geom_input must be invalid. Most likely due to the errors you mentioned above when building the geom input. I would pay attention to each error.

Carole, we can do diagnostics on our users’ code if they can give us completely buildable and debuggable projects. I would prefer a small Visual Studio or Xcode project that won’t take too much time to build and debug. As I am expected to spend my time on my own programming tasks here :smiley:


#11

Hi Bugra,

And thank you so much for your answer.

I understand a little bit more how this works. I’ll check all that (next week though: my schedule got busy) to see if I don’t make a big mistake somewhere and if I still can’t find what happens, I’ll try to build a nice project :smile:

Anyway, thanks again for your help, I really appreciate.

have a good week-end.


#12

Well… bingo !

It seems that I was too confident: it seems that our mesh generation and triangulation algorithms are perfectly able to generate 2 points triangles… and that was the problem…

Sorry for bothering you for just that but I must admit I learnt a lot of things on the SketchUp SDK during this discussion.

So now I guess I am going to rip a few heads off and finish my converter.

Thanks again so much for your help !!

And have a very good day.


#13

:smile: Not a problem. I am glad you found the culprit. These discussion on the forums are great in that it leaves a record for all of us to learn something or refresh our memories later.