The SketchUp C API sample I’m using demonstrates how to read SketchUp files, but I’m not sure how to load the face indices from the associated model.
The code following does works but it just affects the vertex data.
Please check the code below to assist with loading the face indices from the sample code.
#include <slapi/slapi.h> #include <slapi/geometry.h> #include <slapi/initialize.h> #include <slapi/unicodestring.h> #include <slapi/model/model.h> #include <slapi/model/entities.h> #include <slapi/model/face.h> #include <slapi/model/edge.h> #include <slapi/model/vertex.h> #include
int main() {
// Always initialize the API before using it
SUInitialize();
// Load the model from a file
SUModelRef model = SU_INVALID;
SUResult res = SUModelCreateFromFile(&model, “model.skp”);
// 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);
// Get all the faces from the entities object
size_t faceCount = 0;
SUEntitiesGetNumFaces(entities, &faceCount);
if (faceCount > 0) {
std::vector faces(faceCount);
SUEntitiesGetFaces(entities, faceCount, &faces[0], &faceCount);
// Get all the edges in this face
for (size_t i = 0; i < faceCount; i++) {
size_t edgeCount = 0;
SUFaceGetNumEdges(faces[i], &edgeCount);
if (edgeCount > 0) {
std::vector edges(edgeCount);
SUFaceGetEdges(faces[i], edgeCount, &edges[0], &edgeCount);
// Get the vertex positions for each edge
for (size_t j = 0; j < edgeCount; j++) {
SUVertexRef startVertex = SU_INVALID;
SUVertexRef endVertex = SU_INVALID;
SUEdgeGetStartVertex(edges[j], &startVertex);
SUEdgeGetEndVertex(edges[j], &endVertex);
SUPoint3D start;
SUPoint3D end;
SUVertexGetPosition(startVertex, &start);
SUVertexGetPosition(endVertex, &end);
// Now do something with the point data
}
}
}
}
// Get model name
SUStringRef name = SU_INVALID;
SUStringCreate(&name);
SUModelGetName(model, &name);
size_t name_length = 0;
SUStringGetUTF8Length(name, &name_length);
char* name_utf8 = new char[name_length + 1];
SUStringGetUTF8(name, name_length + 1, name_utf8, &name_length);
// Now we have the name in a form we can use
SUStringRelease(&name);
delete name_utf8;
// Must release the model or there will be memory leaks
SUModelRelease(&model);
// Always terminate the API when done using it
SUTerminate();
return 0;
}
Here what I tried so far.
From where can I get the total part/assembly count. I need to fill the data part wise.
Here I am getting triangles for all the parts. How can I get this partwise?
SUInitialize();
Part partData;
Face faceData;
Assembly assembly;
partData.partName = "PartCube";
partData.m_isVisible = true;
size_t EntityCount = 0;
// Load the model from a file
SUModelRef model = SU_INVALID;
SUModelLoadStatus status;
SUResult res = SUModelCreateFromFileWithStatus(&model, path, &status);
// 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) {
std::cout << "Failed creating model from a file" << std::endl;
}
if (status == SUModelLoadStatus_Success_MoreRecent)
{
std::cout
<< "This model was created in a more recent SketchUp version than that of the SDK. "
"It contains data which will not be read. Saving the model over the original file may "
"lead to permanent data loss."
<< std::endl;
}
// Get the entity container of the model.
SUEntitiesRef entities = SU_INVALID;
SUModelGetEntities(model, &entities);
SUEntityListRef list = SU_INVALID;
// Get all the faces from the entities object
size_t faceCount = 0;
SUEntitiesGetNumFaces(entities, &faceCount);
std::cout << "Number of faces: " << faceCount << std::endl;
if (faceCount > 0)
{
std::vector<SUFaceRef> faces(faceCount);
SUEntitiesGetFaces(entities, faceCount, &faces[0], &faceCount);
for (size_t i = 0; i < faceCount; i++)
{
std::vector<double> vertexCoordinate;
std::vector<double> normalCoordinate;
std::vector<int> faceindices;
SUFaceRef faceRef = faces[i];
// Load face geometry.
SUMeshHelperRef polyMesh = SU_INVALID;
SUMeshHelperCreate(&polyMesh, faceRef);
size_t numberOfVertices = 0;
size_t numberOfIndices = 0;
size_t numberOfNormals = 0;
size_t result = 0;
if (SUIsValid(polyMesh))
{
SUMeshHelperGetNumVertices(polyMesh, &numberOfVertices);
std::vector<SUPoint3D> points(numberOfVertices);
std::vector<SUPoint3D> uvs(numberOfVertices);
std::vector<SUPoint3D> backUvs(numberOfVertices);
std::vector<SUVector3D> normals(numberOfVertices);
// Get data from polyMesh
SUMeshHelperGetVertices(polyMesh, numberOfVertices, &points[0], &result);
SUMeshHelperGetNormals(polyMesh, numberOfNormals, &normals[0], &result);
numberOfNormals = result;
SUMeshHelperGetFrontSTQCoords(polyMesh, numberOfVertices, &uvs[0], &result);
SUMeshHelperGetBackSTQCoords(polyMesh, numberOfVertices, &backUvs[0], &result);
// Load indices.
SUMeshHelperGetNumTriangles(polyMesh, &numberOfIndices);
numberOfIndices = numberOfIndices * 3;
std::vector<size_t> indices(numberOfIndices);
SUMeshHelperGetVertexIndices(polyMesh, numberOfIndices, &indices[0], &result);
for (int i = 0; i < numberOfVertices; i++)
{
vertexCoordinate.push_back(points[i].x);
vertexCoordinate.push_back(points[i].y);
vertexCoordinate.push_back(points[i].z);
normalCoordinate.push_back(normals[i].x);
normalCoordinate.push_back(normals[i].y);
normalCoordinate.push_back(normals[i].z);
}
for (const auto& index : indices)
{
faceindices.push_back(static_cast<int>(index));
}
// Release polyMesh helper
SUMeshHelperRelease(&polyMesh);
faceData.coordinates = vertexCoordinate;
faceData.indices = faceindices;
}
partData.faces.push_back(faceData);
faceData.faceColor.red = 160;
faceData.faceColor.green = 160;
faceData.faceColor.blue = 160;
faceData.faceColor.opacity = 255;
}
}
assembly.parts.push_back(partData);
assembly.assemblyName = "Cube";
assembly.m_isVisible = true;
// Get model name
SUStringRef name = SU_INVALID;
SUStringCreate(&name);
SUModelGetName(model, &name);
size_t name_length = 0;
SUStringGetUTF8Length(name, &name_length);
char* name_utf8 = new char[name_length + 1];
SUStringGetUTF8(name, name_length + 1, name_utf8, &name_length);
// Now we have the name in a form we can use
SUStringRelease(&name);
delete[] name_utf8;
// Must release the model or there will be memory leaks
SUResult result = SUModelRelease(&model);
if (result != SU_ERROR_NONE)
{
std::cout << "Reading SketchUp model: Failed" << std::endl;
}
else
{
std::cout << "Reading SketchUp model: Success" << std::endl;
}
// Always terminate the API when done using it
SUTerminate();
You need to learn more about SU scene structure and API.
The simplest way is to play a bit with Ruby API under SketchUp Ruby Console.
The above code can export only a ‘raw’ faces from the ‘root level’.
For components and groups you’ll need to get them from root level entities, and traverse whole scene tree to collect all faces from all instances/groups of all branches of the scene tree.
To get additional information you’ll need to cast object to SUDrawingElementRef(to get visibility, materials, layer info etc) or to SUEntityRef(to get object name, attributes etc).
Hi @RaPIT,
Thanks for the guidance on how to collect the faces from the group and component and how to apply the transformation.
I tried to get the edge data from the model and export them. While doing that I encountered the issue of the transformation. I have collected the edge from the root, group and the component. Please refer the below code on how I traverse the edge from model and the screenshot regarding the issue.
All vertices are in local coordinate system, you’ll need to multiply them by ‘world’ transform, where world transform is parent transform multiplied by local transform.
I’m having trouble maintaining the transparency of a material. After exporting, a transparent object appears solid. Could you please review the snippet and let me know the same?
SUResult res = SUFaceGetFrontMaterial(face, &front_material);
// Get the color from the material
if (res == SU_ERROR_NONE)
{
res = SUMaterialGetColor(front_material, &face_color);
}
Hi DanRathbun,
Thanks for the reply. We have invetsigated the issue at our end and observed that when we attempt to get the front material using the method SU_RESULT SUFaceGetFrontMaterial(SUFaceRef face, SUMaterialRef* material); we are not getting the appropriate material value, preventing us from fetching and setting the face color of the material. Our model has three transparent green pendants. During export, two out of three exported successfully, while the remaining one exported with default RGBA value because we are not getting the ‘front_material’ from it.
SUResult res = SUFaceGetFrontMaterial(face, &front_material);
// Get the color from the material
if (res == SU_ERROR_NONE)
{
res = SUMaterialGetColor(front_material, &face_color);
}
else
{
face_color.red = 128;
face_color.green = 128;
face_color.blue = 128;
face_color.alpha = 255;
}
Please refer to the attached sketch up file for you reference Green+pendant+light.skp (173.2 KB)
Which group is the problem group ? They differ in nesting level and whether the outer group or the internal faces are assigned a material or not.
If you had painted them each a different color it would be a better test, IMO.
Also, the code you posted is not a complete working code snippet. It does not for example assign gray color to any faces or groups, yet there are groups assigned a gray color (even though the faces within are painted green. NOTE: SketchUp uses face color to override group color in its display engine.)
I also notice in the model that some faces have material assigned to both the front and back sides. Others only one side. Switching to monochrome style it looks like all the faces are properly front-side-out.