2015-05-19 03:48:29 +00:00
|
|
|
/*
|
|
|
|
Open Asset Import Library (assimp)
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
|
2021-02-28 11:17:54 +00:00
|
|
|
Copyright (c) 2006-2021, assimp team
|
2018-01-28 18:42:05 +00:00
|
|
|
|
2017-05-09 17:57:36 +00:00
|
|
|
|
2015-05-19 03:48:29 +00:00
|
|
|
All rights reserved.
|
|
|
|
|
2015-05-19 03:52:10 +00:00
|
|
|
Redistribution and use of this software in source and binary forms,
|
|
|
|
with or without modification, are permitted provided that the
|
2015-05-19 03:48:29 +00:00
|
|
|
following conditions are met:
|
|
|
|
|
|
|
|
* Redistributions of source code must retain the above
|
|
|
|
copyright notice, this list of conditions and the
|
|
|
|
following disclaimer.
|
|
|
|
|
|
|
|
* Redistributions in binary form must reproduce the above
|
|
|
|
copyright notice, this list of conditions and the
|
|
|
|
following disclaimer in the documentation and/or other
|
|
|
|
materials provided with the distribution.
|
|
|
|
|
|
|
|
* Neither the name of the assimp team, nor the names of its
|
|
|
|
contributors may be used to endorse or promote products
|
|
|
|
derived from this software without specific prior
|
|
|
|
written permission of the assimp team.
|
|
|
|
|
2015-05-19 03:52:10 +00:00
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
2015-05-19 03:48:29 +00:00
|
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
2015-05-19 03:52:10 +00:00
|
|
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
2015-05-19 03:48:29 +00:00
|
|
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
2015-05-19 03:52:10 +00:00
|
|
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
2015-05-19 03:48:29 +00:00
|
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
2015-05-19 03:52:10 +00:00
|
|
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
2015-05-19 03:48:29 +00:00
|
|
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if !defined(ASSIMP_BUILD_NO_EXPORT) && !defined(ASSIMP_BUILD_NO_STL_EXPORTER)
|
|
|
|
|
|
|
|
#include "STLExporter.h"
|
2016-06-06 20:04:29 +00:00
|
|
|
#include <assimp/version.h>
|
|
|
|
#include <assimp/IOSystem.hpp>
|
|
|
|
#include <assimp/scene.h>
|
|
|
|
#include <assimp/Exporter.hpp>
|
2016-04-05 21:23:53 +00:00
|
|
|
#include <memory>
|
2018-01-06 00:18:33 +00:00
|
|
|
#include <assimp/Exceptional.h>
|
|
|
|
#include <assimp/ByteSwapper.h>
|
2015-05-19 03:48:29 +00:00
|
|
|
|
|
|
|
using namespace Assimp;
|
2018-05-01 07:06:22 +00:00
|
|
|
|
2015-05-19 03:57:13 +00:00
|
|
|
namespace Assimp {
|
2015-05-19 03:48:29 +00:00
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
// Worker function for exporting a scene to Stereolithograpy. Prototyped and registered in Exporter.cpp
|
2018-05-01 07:06:22 +00:00
|
|
|
void ExportSceneSTL(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties )
|
2015-05-19 03:48:29 +00:00
|
|
|
{
|
2018-05-01 07:06:22 +00:00
|
|
|
bool exportPointClouds = pProperties->GetPropertyBool(AI_CONFIG_EXPORT_POINT_CLOUDS);
|
|
|
|
|
2015-05-19 03:57:13 +00:00
|
|
|
// invoke the exporter
|
2018-05-01 07:06:22 +00:00
|
|
|
STLExporter exporter(pFile, pScene, exportPointClouds );
|
2015-05-19 03:48:29 +00:00
|
|
|
|
2017-10-09 13:47:17 +00:00
|
|
|
if (exporter.mOutput.fail()) {
|
|
|
|
throw DeadlyExportError("output data creation failed. Most likely the file became too large: " + std::string(pFile));
|
|
|
|
}
|
|
|
|
|
2015-05-19 03:57:13 +00:00
|
|
|
// we're still here - export successfully completed. Write the file.
|
2016-04-05 21:23:53 +00:00
|
|
|
std::unique_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wt"));
|
2020-06-23 19:05:42 +00:00
|
|
|
if (outfile == nullptr) {
|
2015-05-19 03:57:13 +00:00
|
|
|
throw DeadlyExportError("could not open output .stl file: " + std::string(pFile));
|
|
|
|
}
|
2015-05-19 03:48:29 +00:00
|
|
|
|
2015-05-19 03:57:13 +00:00
|
|
|
outfile->Write( exporter.mOutput.str().c_str(), static_cast<size_t>(exporter.mOutput.tellp()),1);
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
2018-05-01 07:06:22 +00:00
|
|
|
void ExportSceneSTLBinary(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties )
|
2015-05-19 03:48:29 +00:00
|
|
|
{
|
2018-05-01 07:06:22 +00:00
|
|
|
bool exportPointClouds = pProperties->GetPropertyBool(AI_CONFIG_EXPORT_POINT_CLOUDS);
|
|
|
|
|
2015-05-19 03:57:13 +00:00
|
|
|
// invoke the exporter
|
2018-05-01 07:06:22 +00:00
|
|
|
STLExporter exporter(pFile, pScene, exportPointClouds, true);
|
2015-05-19 03:48:29 +00:00
|
|
|
|
2017-10-09 13:47:17 +00:00
|
|
|
if (exporter.mOutput.fail()) {
|
|
|
|
throw DeadlyExportError("output data creation failed. Most likely the file became too large: " + std::string(pFile));
|
|
|
|
}
|
|
|
|
|
2015-05-19 03:57:13 +00:00
|
|
|
// we're still here - export successfully completed. Write the file.
|
2016-04-05 21:23:53 +00:00
|
|
|
std::unique_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wb"));
|
2020-06-23 19:05:42 +00:00
|
|
|
if (outfile == nullptr) {
|
2015-05-19 03:57:13 +00:00
|
|
|
throw DeadlyExportError("could not open output .stl file: " + std::string(pFile));
|
|
|
|
}
|
2015-05-19 03:48:29 +00:00
|
|
|
|
2015-05-19 03:57:13 +00:00
|
|
|
outfile->Write( exporter.mOutput.str().c_str(), static_cast<size_t>(exporter.mOutput.tellp()),1);
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // end of namespace Assimp
|
|
|
|
|
2018-05-01 11:41:39 +00:00
|
|
|
static const char *SolidToken = "solid";
|
|
|
|
static const char *EndSolidToken = "endsolid";
|
2015-05-19 03:48:29 +00:00
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2018-05-01 07:06:22 +00:00
|
|
|
STLExporter::STLExporter(const char* _filename, const aiScene* pScene, bool exportPointClouds, bool binary)
|
2015-05-19 03:48:29 +00:00
|
|
|
: filename(_filename)
|
|
|
|
, endl("\n")
|
|
|
|
{
|
2015-05-19 03:57:13 +00:00
|
|
|
// make sure that all formatting happens using the standard, C locale and not the user's current locale
|
|
|
|
const std::locale& l = std::locale("C");
|
|
|
|
mOutput.imbue(l);
|
2019-06-20 17:11:11 +00:00
|
|
|
mOutput.precision(ASSIMP_AI_REAL_TEXT_PRECISION);
|
2015-05-19 03:57:13 +00:00
|
|
|
if (binary) {
|
|
|
|
char buf[80] = {0} ;
|
|
|
|
buf[0] = 'A'; buf[1] = 's'; buf[2] = 's'; buf[3] = 'i'; buf[4] = 'm'; buf[5] = 'p';
|
|
|
|
buf[6] = 'S'; buf[7] = 'c'; buf[8] = 'e'; buf[9] = 'n'; buf[10] = 'e';
|
|
|
|
mOutput.write(buf, 80);
|
|
|
|
unsigned int meshnum = 0;
|
|
|
|
for(unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
|
|
|
for (unsigned int j = 0; j < pScene->mMeshes[i]->mNumFaces; ++j) {
|
|
|
|
meshnum++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
AI_SWAP4(meshnum);
|
|
|
|
mOutput.write((char *)&meshnum, 4);
|
2018-05-01 07:06:22 +00:00
|
|
|
|
|
|
|
if (exportPointClouds) {
|
2019-03-30 18:12:13 +00:00
|
|
|
throw DeadlyExportError("This functionality is not yet implemented for binary output.");
|
2018-05-01 07:06:22 +00:00
|
|
|
}
|
|
|
|
|
2015-05-19 03:57:13 +00:00
|
|
|
for(unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
|
|
|
WriteMeshBinary(pScene->mMeshes[i]);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
|
2018-05-01 07:06:22 +00:00
|
|
|
// Exporting only point clouds
|
|
|
|
if (exportPointClouds) {
|
2018-05-01 11:41:39 +00:00
|
|
|
WritePointCloud("Assimp_Pointcloud", pScene );
|
2018-05-01 07:06:22 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-05-01 11:41:39 +00:00
|
|
|
// Export the assimp mesh
|
|
|
|
const std::string name = "AssimpScene";
|
2018-05-01 13:06:56 +00:00
|
|
|
mOutput << SolidToken << " " << name << endl;
|
2015-05-19 03:57:13 +00:00
|
|
|
for(unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
2018-05-01 11:41:39 +00:00
|
|
|
WriteMesh(pScene->mMeshes[ i ]);
|
|
|
|
}
|
2021-01-20 08:29:30 +00:00
|
|
|
mOutput << EndSolidToken << " " << name << endl;
|
2018-05-01 11:41:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
|
void STLExporter::WritePointCloud(const std::string &name, const aiScene* pScene) {
|
|
|
|
mOutput << " " << SolidToken << " " << name << endl;
|
|
|
|
aiVector3D nor;
|
|
|
|
mOutput << " facet normal " << nor.x << " " << nor.y << " " << nor.z << endl;
|
|
|
|
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
|
|
|
aiMesh *mesh = pScene->mMeshes[i];
|
|
|
|
if (nullptr == mesh) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (unsigned int a = 0; a < mesh->mNumVertices; ++a) {
|
|
|
|
const aiVector3D& v = mesh->mVertices[a];
|
|
|
|
mOutput << " vertex " << v.x << " " << v.y << " " << v.z << endl;
|
|
|
|
mOutput << " vertex " << v.x << " " << v.y << " " << v.z << endl;
|
|
|
|
mOutput << " vertex " << v.x << " " << v.y << " " << v.z << endl;
|
2015-05-19 03:57:13 +00:00
|
|
|
}
|
|
|
|
}
|
2018-05-01 13:06:56 +00:00
|
|
|
mOutput << EndSolidToken << " " << name << endl;
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
2018-05-01 11:28:53 +00:00
|
|
|
void STLExporter::WriteMesh(const aiMesh* m)
|
2015-05-19 03:48:29 +00:00
|
|
|
{
|
2015-05-19 03:57:13 +00:00
|
|
|
for (unsigned int i = 0; i < m->mNumFaces; ++i) {
|
|
|
|
const aiFace& f = m->mFaces[i];
|
|
|
|
|
|
|
|
// we need per-face normals. We specified aiProcess_GenNormals as pre-requisite for this exporter,
|
|
|
|
// but nonetheless we have to expect per-vertex normals.
|
|
|
|
aiVector3D nor;
|
|
|
|
if (m->mNormals) {
|
|
|
|
for(unsigned int a = 0; a < f.mNumIndices; ++a) {
|
|
|
|
nor += m->mNormals[f.mIndices[a]];
|
|
|
|
}
|
2018-05-01 13:06:56 +00:00
|
|
|
nor.NormalizeSafe();
|
2015-05-19 03:57:13 +00:00
|
|
|
}
|
|
|
|
mOutput << " facet normal " << nor.x << " " << nor.y << " " << nor.z << endl;
|
|
|
|
mOutput << " outer loop" << endl;
|
|
|
|
for(unsigned int a = 0; a < f.mNumIndices; ++a) {
|
|
|
|
const aiVector3D& v = m->mVertices[f.mIndices[a]];
|
|
|
|
mOutput << " vertex " << v.x << " " << v.y << " " << v.z << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
mOutput << " endloop" << endl;
|
|
|
|
mOutput << " endfacet" << endl << endl;
|
|
|
|
}
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
2018-05-01 13:06:56 +00:00
|
|
|
void STLExporter::WriteMeshBinary(const aiMesh* m)
|
2015-05-19 03:48:29 +00:00
|
|
|
{
|
2015-05-19 03:57:13 +00:00
|
|
|
for (unsigned int i = 0; i < m->mNumFaces; ++i) {
|
|
|
|
const aiFace& f = m->mFaces[i];
|
|
|
|
// we need per-face normals. We specified aiProcess_GenNormals as pre-requisite for this exporter,
|
|
|
|
// but nonetheless we have to expect per-vertex normals.
|
|
|
|
aiVector3D nor;
|
|
|
|
if (m->mNormals) {
|
|
|
|
for(unsigned int a = 0; a < f.mNumIndices; ++a) {
|
|
|
|
nor += m->mNormals[f.mIndices[a]];
|
|
|
|
}
|
|
|
|
nor.Normalize();
|
|
|
|
}
|
2018-03-06 18:55:32 +00:00
|
|
|
// STL binary files use 4-byte floats. This may possibly cause loss of precision
|
|
|
|
// for clients using 8-byte doubles
|
|
|
|
float nx = (float) nor.x;
|
|
|
|
float ny = (float) nor.y;
|
|
|
|
float nz = (float) nor.z;
|
2015-05-19 03:57:13 +00:00
|
|
|
AI_SWAP4(nx); AI_SWAP4(ny); AI_SWAP4(nz);
|
|
|
|
mOutput.write((char *)&nx, 4); mOutput.write((char *)&ny, 4); mOutput.write((char *)&nz, 4);
|
|
|
|
for(unsigned int a = 0; a < f.mNumIndices; ++a) {
|
|
|
|
const aiVector3D& v = m->mVertices[f.mIndices[a]];
|
2018-03-06 18:55:32 +00:00
|
|
|
float vx = (float) v.x, vy = (float) v.y, vz = (float) v.z;
|
2015-05-19 03:57:13 +00:00
|
|
|
AI_SWAP4(vx); AI_SWAP4(vy); AI_SWAP4(vz);
|
|
|
|
mOutput.write((char *)&vx, 4); mOutput.write((char *)&vy, 4); mOutput.write((char *)&vz, 4);
|
|
|
|
}
|
|
|
|
char dummy[2] = {0};
|
|
|
|
mOutput.write(dummy, 2);
|
|
|
|
}
|
2015-05-19 03:48:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|