When I clean all entity, I cannot save the model!

when I clean all entity, I cannot save the model. I got SU_ERROR_SERIALIZATION.

2426.skp (5.2 MB)


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

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

	// get the model from test_src.skp  =>  src_model
	SU(SUModelCreateFromFileWithStatus(&src_model, "F:/Desktop/temp/2426.skp", &loadStatus));
	// get entities of model
	SUEntitiesRef model_entities = SU_INVALID;
	SU(SUModelGetEntities(src_model, &model_entities));

	// clear all entity
	SUEntityListRef entList = SU_INVALID;
	SU(SUEntitiesEntityListFill(model_entities, SURefType_DrawingElement, entList));
	std::vector<SUEntityRef> erase_ents;

	SUEntityListIteratorRef iter_ent = SU_INVALID;
	if (SUEntityListBegin(entList, &iter_ent) == SU_ERROR_NONE) {
		while (true) {
			bool b_inRange = true;
			SU(SUEntityListIteratorIsInRange(iter_ent, &b_inRange))
			if (!b_inRange) break;

			SUEntityRef ent = SU_INVALID;
			SU(SUEntityListIteratorGetEntity(iter_ent, &ent));

			if (SUEntityListIteratorNext(iter_ent) != SU_ERROR_NONE) break;

	SU(SUEntitiesErase(model_entities, erase_ents.size(), &erase_ents[0]));
	SUResult res = SUModelSaveToFile(src_model, "F:/Desktop/temp/1.skp");

	if (res != SU_ERROR_NONE) {
		printf("FAIL. %d \n", res);
	return 0;

I can reproduce this. Not sure why this is failing though. Can you report this in the issue tracker please? GitHub - SketchUp/api-issue-tracker: Public issue tracker for the SketchUp and LayOut's APIs

1 Like

Each scene in a model maintains a list of hidden entities (the lists is adjusted when the user ‘updates’ a scene). For better or worse, these lists are not upated automatically when entities are erased via calls to the API leaving that task to the API user. We need to check each scene for hidden entities and remove these references before the model can be saved. Perhaps someone with more experience will point us to built in function to accomplish this task.

Below is an example routine that visits each scene and unhides each hidden entity. A complete working example of this routine merged with the code you posted previously can be found in the file attached at the bottom of this post.

// Iterate the scenes in the model and unhide any hidden entities
size_t sceneCount = 0;
SU(SUModelGetNumScenes(srcModel, &sceneCount));

if (sceneCount > 0) {
  size_t sceneCountRet = 0;
  std::vector<SUSceneRef> scenes(sceneCount);
  SU(SUModelGetScenes(srcModel, sceneCount, &scenes[0], &sceneCountRet));

  for (size_t sceneIndex = 0; sceneIndex < sceneCountRet; sceneIndex++) {
    SUSceneRef currentScene = scenes[sceneIndex];

    //  get hidden entities for currentScene
    size_t hiddenCount = 0;
    SUSceneGetNumHiddenEntities(currentScene, &hiddenCount);

    if (hiddenCount > 0 ) {
      size_t hiddenCountRet = 0;
      std::vector<SUEntityRef> hiddenEntities(hiddenCount);
      SU(SUSceneGetHiddenEntities(scenes[sceneIndex], hiddenCount, &hiddenEntities[0], &hiddenCountRet));
      printf("Found %d hidden entities\n", (int)hiddenCountRet);

      for (size_t hiddenIndex = 0; hiddenIndex < hiddenCountRet; hiddenIndex++) {
        int32_t entity_id;
        SU(SUEntityGetID(hiddenEntities[hiddenIndex], &entity_id));
        printf("Found hidden entity %d\n", (int)entity_id);
        SUDrawingElementRef elementRef = SUDrawingElementFromEntity(hiddenEntities[hiddenIndex]);
        SU(SUSceneSetDrawingElementHidden(scenes[sceneIndex], elementRef, false));
    } // end if hiddenCount
} // end if sceneCount

CleanSKPFile.cpp.txt (3.0 KB)


2426.skp is ok. But I find other file is not ok.

Since you’re deleting all of the sections planes from the model entities you’ll need to turn off the UseSectionPlanes flag for each scene. Otherwise we either fail to save the file or throw a memory access violation. A sad experience in either case.

The fix is to add this single line:

SU(SUSceneSetUseSectionPlanes(currentScene, false));

after this line:

SUSceneRef currentScene = scenes[sceneIndex];

I didn’t think of that.Just try to clear all related content.
Thank u.
And this method(SUEntitiesClear) has not been found before.

We have reproduced and identified a bug in SUEntitiesClear. It is expected to work as the original post tried to use it.

1 Like