Hi everyone,
I have a.skp file representing a house, and I use the function SUComponentInstanceSaveAs to isolate some of its elements in another temporary file, which I then read using SUModelCreateFromFile.
It works fine for several test cases, but I just got a new one and there is one element (one of the walls of the house) which leads to a SU_ERROR_SERIALIZATION when calling SUModelCreateFromFile, while the corresponding call to SUComponentInstanceSaveAs seems to work fine (at least it returns SU_ERROR_NONE)
I really don’t get what’s wrong and I wonder if anyone has ever experienced such an issue?
Could something be wrong in the original model of the house?
Any help would be appreciated. I can provide the original .skp if need be.
Regards,
Donat
The SUComponentInstanceSaveAs
API function has serious issues which have been logged in the official API issue tracker:
opened 03:54PM - 04 Oct 19 UTC
closed 03:51PM - 08 Feb 22 UTC
bug
wontfix
C API
SketchUp
logged
The issue is that SUComponentInstanceGetTransform always returns identity when r… equesting on a parsed component instance from a [model skp file](https://forums.sketchup.com/uploads/short-url/aWMKUyX8PiMCa4IAIGC2CnaCjyn.skp).
Consider the following code:
```cpp
#include <stdio.h>
#include <iostream>
#include <SketchUpAPI/common.h>
#include <SketchUpAPI/geometry.h>
#include <SketchUpAPI/initialize.h>
#include <SketchUpAPI/model/model.h>
#include <SketchUpAPI/model/entities.h>
#include <SketchUpAPI/model/face.h>
#include <SketchUpAPI/model/edge.h>
#include <SketchUpAPI/model/vertex.h>
#include <SketchUpAPI/model/component_definition.h>
#include <SketchUpAPI/model/component_instance.h>
#include <SketchUpAPI/geometry/transformation.h>
int main(int n, char **args) {
// Always initialize the API before using it
SUInitialize();
if (n > 1 && !strcmp(1[args], "display"))
{
SUModelRef model = SU_INVALID;
SUModelCreateFromFile(&model, "new_model.skp");
SUEntitiesRef entities = SU_INVALID;
SUModelGetEntities(model, &entities);
size_t count = 0;
SUEntitiesGetNumInstances(entities, &count);
std::cout << "instance count: " << count << "\n";
SUComponentInstanceRef* instances = (SUComponentInstanceRef*)_alloca(count * sizeof * instances);
size_t szinstances;
SUEntitiesGetInstances(entities, count, instances, &szinstances);
std::cout << "returned instances count: " << szinstances << "\n";
while (szinstances--)
{
struct SUTransformation matrix;
SUComponentInstanceGetTransform(instances[szinstances], &matrix);
struct FloatingPosition {
double x, z, y, d;
} pos = { .x = matrix.values[12], .z = matrix.values[14], .y = matrix.values[13], .d = matrix.values[15] };
printf("%f, %f, %f\n", pos.x, pos.y, pos.z);
}
return 0;
}
// Create an empty model
SUModelRef model = SU_INVALID;
SUResult res = SUModelCreate(&model);
// It's best to always check the return code from each SU function call.
// Only showing this check once to keep this example short.
if (res != SU_ERROR_NONE)
return 1;
// Get the entity container of the model
SUEntitiesRef entities = SU_INVALID;
SUModelGetEntities(model, &entities);
// Create a loop input describing the vertex ordering for a face's outer loop
SULoopInputRef outer_loop = SU_INVALID;
SULoopInputCreate(&outer_loop);
for (size_t i = 0; i < 4; ++i) {
SULoopInputAddVertexIndex(outer_loop, i);
}
// Create the face
SUFaceRef face = SU_INVALID;
SUPoint3D vertices[4] = { { 0, 0, 0 },
{ 100, 100, 0 },
{ 100, 100, 100 },
{ 0, 0, 100 } };
SUFaceCreate(&face, vertices, &outer_loop);
// Add the face to the entities
SUComponentDefinitionRef def = SU_INVALID;
SUComponentDefinitionCreate(&def);
SUEntitiesRef defentities = SU_INVALID;
SUComponentDefinitionGetEntities(def, &defentities);
SUEntitiesAddFaces(defentities, 1, &face);
SUComponentInstanceRef instance = SU_INVALID;
SUComponentDefinitionCreateInstance(def, &instance);
static SUTransformation matrixtransform;
constexpr SUVector3D point = { 666, 666, 666 };
SUTransformationTranslation(&matrixtransform, &point);
SUComponentInstanceSetTransform(instance, &matrixtransform);
SUEntitiesAddInstance(entities, instance, nullptr);
//comment the next line to make it work
SUComponentInstanceSaveAs(instance, "instance.skp");
// Save the in-memory model to a file
res = SUModelSaveToFile(model, "new_model.skp");
// Must release the model or there will be memory leaks
SUModelRelease(&model);
// Always terminate the API when done using it
SUTerminate();
if (res != SU_ERROR_NONE) {
std::cout << "Unable to save document!";
return 1;
}
std::cout << "Document saved!";
return 0;
}
```
I'm using SDK_WIN_x64_2019-2-222. The above code will always print 0.000000, 0.000000, 0.000000 - component_instance_name - no matter if the component instance have any transformation taken in place (I exported them to skp with a transformation).
opened 04:19PM - 24 Mar 18 UTC
closed 03:50PM - 08 Feb 22 UTC
C API
SketchUp
logged
documentation
### C API Documentation Issue
#### [**`SUComponentInstanceSaveAs()`**](https:… //extensions.sketchup.com/developers/sketchup_c_api/sketchup/struct_s_u_component_instance_ref.html#add89b2be37466aa7499213e5289911cd)
> **DEPRECATED**: at API v10.0, SketchUp release 2022.0
New code should update to API v10.0 (or higher) and use the [`SUComponentDefinitionSaveToFile()`](https://extensions.sketchup.com/developers/sketchup_c_api/sketchup/struct_s_u_component_definition_ref.html#a98735078e64bf09c9f6ff04d295b9b88) function.
The 2nd parameter ...
`[in] file_path The file path destination of the serialization operation. Assumed to be UTF-8 encoded.
`
What does **_serialization_** mean here ?
Is this function meant to save out to a component SKP file ?
----
Confused because the Ruby API has **no** "save_as" method for the Instance class, but **does** have one for the Definition class. The C API has a "save_as" for the Instance object but **not** the Definition.
> **NOTE**: Fixed at API v10.0 with addition of the [`SUComponentDefinitionSaveToFile()`](https://extensions.sketchup.com/developers/sketchup_c_api/sketchup/struct_s_u_component_definition_ref.html#a98735078e64bf09c9f6ff04d295b9b88) function.
So referring to my "Scenario 2" in: https://github.com/SketchUp/api-issue-tracker/issues/70#issuecomment-375902656, it looks as though there is only a Ruby solution at present, for a batch mode means of correcting incorrectly nested DC files.
> **EDIT**: (2022-01-27) Revisiting, it appears that this would be doable since SketchUp 2019.2, API 7.1, when the ability to remove the unneeded wrapping definition was added with the [`SUModelRemoveComponentDefinitions()`](https://extensions.sketchup.com/developers/sketchup_c_api/sketchup/struct_s_u_model_ref.html#a33a670a5502718627a555e645e0e406a) function.
.
Before the definition removal, a copy of the nested DC instance would need to be added to the model's entities collection at the origin, and any (especially dynamic) attribute dictionaries copied to the new instance.
.
The dictionary copying chore could be avoided if running API v10.0, SketchUp release 2022.0 (or higher) and use the [`SUComponentDefinitionSaveToFile()`](https://extensions.sketchup.com/developers/sketchup_c_api/sketchup/struct_s_u_component_definition_ref.html#a98735078e64bf09c9f6ff04d295b9b88) function to save out the nested DC to a standalone file, then close and delete the "wrapped" component file. Lastly rename the new "unwrapped" DC component file in the local component collection folder to the old name.