vrshoot
diff libs/assimp/DXFLoader.cpp @ 0:b2f14e535253
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 01 Feb 2014 19:58:19 +0200 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libs/assimp/DXFLoader.cpp Sat Feb 01 19:58:19 2014 +0200 1.3 @@ -0,0 +1,913 @@ 1.4 +/* 1.5 +--------------------------------------------------------------------------- 1.6 +Open Asset Import Library (assimp) 1.7 +--------------------------------------------------------------------------- 1.8 + 1.9 +Copyright (c) 2006-2012, assimp team 1.10 + 1.11 +All rights reserved. 1.12 + 1.13 +Redistribution and use of this software in source and binary forms, 1.14 +with or without modification, are permitted provided that the following 1.15 +conditions are met: 1.16 + 1.17 +* Redistributions of source code must retain the above 1.18 + copyright notice, this list of conditions and the 1.19 + following disclaimer. 1.20 + 1.21 +* Redistributions in binary form must reproduce the above 1.22 + copyright notice, this list of conditions and the 1.23 + following disclaimer in the documentation and/or other 1.24 + materials provided with the distribution. 1.25 + 1.26 +* Neither the name of the assimp team, nor the names of its 1.27 + contributors may be used to endorse or promote products 1.28 + derived from this software without specific prior 1.29 + written permission of the assimp team. 1.30 + 1.31 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.32 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.33 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.34 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.35 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.36 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.37 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.38 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.39 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.40 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.41 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.42 +--------------------------------------------------------------------------- 1.43 +*/ 1.44 + 1.45 +/** @file DXFLoader.cpp 1.46 + * @brief Implementation of the DXF importer class 1.47 + */ 1.48 + 1.49 +#include "AssimpPCH.h" 1.50 +#ifndef ASSIMP_BUILD_NO_DXF_IMPORTER 1.51 + 1.52 +#include "DXFLoader.h" 1.53 +#include "ParsingUtils.h" 1.54 +#include "ConvertToLHProcess.h" 1.55 +#include "fast_atof.h" 1.56 + 1.57 +#include "DXFHelper.h" 1.58 + 1.59 +using namespace Assimp; 1.60 + 1.61 +// AutoCAD Binary DXF<CR><LF><SUB><NULL> 1.62 +#define AI_DXF_BINARY_IDENT ("AutoCAD Binary DXF\r\n\x1a\0") 1.63 +#define AI_DXF_BINARY_IDENT_LEN (24) 1.64 + 1.65 +// default vertex color that all uncolored vertices will receive 1.66 +#define AI_DXF_DEFAULT_COLOR aiColor4D(0.6f,0.6f,0.6f,0.6f) 1.67 + 1.68 +// color indices for DXF - 16 are supported, the table is 1.69 +// taken directly from the DXF spec. 1.70 +static aiColor4D g_aclrDxfIndexColors[] = 1.71 +{ 1.72 + aiColor4D (0.6f, 0.6f, 0.6f, 1.0f), 1.73 + aiColor4D (1.0f, 0.0f, 0.0f, 1.0f), // red 1.74 + aiColor4D (0.0f, 1.0f, 0.0f, 1.0f), // green 1.75 + aiColor4D (0.0f, 0.0f, 1.0f, 1.0f), // blue 1.76 + aiColor4D (0.3f, 1.0f, 0.3f, 1.0f), // light green 1.77 + aiColor4D (0.3f, 0.3f, 1.0f, 1.0f), // light blue 1.78 + aiColor4D (1.0f, 0.3f, 0.3f, 1.0f), // light red 1.79 + aiColor4D (1.0f, 0.0f, 1.0f, 1.0f), // pink 1.80 + aiColor4D (1.0f, 0.6f, 0.0f, 1.0f), // orange 1.81 + aiColor4D (0.6f, 0.3f, 0.0f, 1.0f), // dark orange 1.82 + aiColor4D (1.0f, 1.0f, 0.0f, 1.0f), // yellow 1.83 + aiColor4D (0.3f, 0.3f, 0.3f, 1.0f), // dark gray 1.84 + aiColor4D (0.8f, 0.8f, 0.8f, 1.0f), // light gray 1.85 + aiColor4D (0.0f, 00.f, 0.0f, 1.0f), // black 1.86 + aiColor4D (1.0f, 1.0f, 1.0f, 1.0f), // white 1.87 + aiColor4D (0.6f, 0.0f, 1.0f, 1.0f) // violet 1.88 +}; 1.89 +#define AI_DXF_NUM_INDEX_COLORS (sizeof(g_aclrDxfIndexColors)/sizeof(g_aclrDxfIndexColors[0])) 1.90 +#define AI_DXF_ENTITIES_MAGIC_BLOCK "$ASSIMP_ENTITIES_MAGIC" 1.91 + 1.92 + 1.93 +static const aiImporterDesc desc = { 1.94 + "Drawing Interchange Format (DXF) Importer", 1.95 + "", 1.96 + "", 1.97 + "", 1.98 + aiImporterFlags_SupportTextFlavour | aiImporterFlags_LimitedSupport, 1.99 + 0, 1.100 + 0, 1.101 + 0, 1.102 + 0, 1.103 + "dxf" 1.104 +}; 1.105 + 1.106 +// ------------------------------------------------------------------------------------------------ 1.107 +// Constructor to be privately used by Importer 1.108 +DXFImporter::DXFImporter() 1.109 +{} 1.110 + 1.111 +// ------------------------------------------------------------------------------------------------ 1.112 +// Destructor, private as well 1.113 +DXFImporter::~DXFImporter() 1.114 +{} 1.115 + 1.116 +// ------------------------------------------------------------------------------------------------ 1.117 +// Returns whether the class can handle the format of the given file. 1.118 +bool DXFImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const 1.119 +{ 1.120 + return SimpleExtensionCheck(pFile,"dxf"); 1.121 +} 1.122 + 1.123 +// ------------------------------------------------------------------------------------------------ 1.124 +// Get a list of all supported file extensions 1.125 +const aiImporterDesc* DXFImporter::GetInfo () const 1.126 +{ 1.127 + return &desc; 1.128 +} 1.129 + 1.130 +// ------------------------------------------------------------------------------------------------ 1.131 +// Imports the given file into the given scene structure. 1.132 +void DXFImporter::InternReadFile( const std::string& pFile, 1.133 + aiScene* pScene, 1.134 + IOSystem* pIOHandler) 1.135 +{ 1.136 + boost::shared_ptr<IOStream> file = boost::shared_ptr<IOStream>( pIOHandler->Open( pFile) ); 1.137 + 1.138 + // Check whether we can read the file 1.139 + if( file.get() == NULL) { 1.140 + throw DeadlyImportError( "Failed to open DXF file " + pFile + ""); 1.141 + } 1.142 + 1.143 + // check whether this is a binaray DXF file - we can't read binary DXF files :-( 1.144 + char buff[AI_DXF_BINARY_IDENT_LEN+1] = {0}; 1.145 + file->Read(buff,AI_DXF_BINARY_IDENT_LEN,1); 1.146 + 1.147 + if (!strncmp(AI_DXF_BINARY_IDENT,buff,AI_DXF_BINARY_IDENT_LEN)) { 1.148 + throw DeadlyImportError("DXF: Binary files are not supported at the moment"); 1.149 + } 1.150 + 1.151 + // DXF files can grow very large, so read them via the StreamReader, 1.152 + // which will choose a suitable strategy. 1.153 + file->Seek(0,aiOrigin_SET); 1.154 + StreamReaderLE stream( file ); 1.155 + 1.156 + DXF::LineReader reader (stream); 1.157 + DXF::FileData output; 1.158 + 1.159 + // now get all lines of the file and process top-level sections 1.160 + bool eof = false; 1.161 + while(!reader.End()) { 1.162 + 1.163 + // blocks table - these 'build blocks' are later (in ENTITIES) 1.164 + // referenced an included via INSERT statements. 1.165 + if (reader.Is(2,"BLOCKS")) { 1.166 + ParseBlocks(reader,output); 1.167 + continue; 1.168 + } 1.169 + 1.170 + // primary entity table 1.171 + if (reader.Is(2,"ENTITIES")) { 1.172 + ParseEntities(reader,output); 1.173 + continue; 1.174 + } 1.175 + 1.176 + // skip unneeded sections entirely to avoid any problems with them 1.177 + // alltogether. 1.178 + else if (reader.Is(2,"CLASSES") || reader.Is(2,"TABLES")) { 1.179 + SkipSection(reader); 1.180 + continue; 1.181 + } 1.182 + 1.183 + else if (reader.Is(2,"HEADER")) { 1.184 + ParseHeader(reader,output); 1.185 + continue; 1.186 + } 1.187 + 1.188 + // comments 1.189 + else if (reader.Is(999)) { 1.190 + DefaultLogger::get()->info("DXF Comment: " + reader.Value()); 1.191 + } 1.192 + 1.193 + // don't read past the official EOF sign 1.194 + else if (reader.Is(0,"EOF")) { 1.195 + eof = true; 1.196 + break; 1.197 + } 1.198 + 1.199 + ++reader; 1.200 + } 1.201 + if (!eof) { 1.202 + DefaultLogger::get()->warn("DXF: EOF reached, but did not encounter DXF EOF marker"); 1.203 + } 1.204 + 1.205 + ConvertMeshes(pScene,output); 1.206 + 1.207 + // Now rotate the whole scene by 90 degrees around the x axis to convert from AutoCAD's to Assimp's coordinate system 1.208 + pScene->mRootNode->mTransformation = aiMatrix4x4( 1.209 + 1.f,0.f,0.f,0.f, 1.210 + 0.f,0.f,1.f,0.f, 1.211 + 0.f,-1.f,0.f,0.f, 1.212 + 0.f,0.f,0.f,1.f) * pScene->mRootNode->mTransformation; 1.213 +} 1.214 + 1.215 +// ------------------------------------------------------------------------------------------------ 1.216 +void DXFImporter::ConvertMeshes(aiScene* pScene, DXF::FileData& output) 1.217 +{ 1.218 + // the process of resolving all the INSERT statements can grow the 1.219 + // polycount excessively, so log the original number. 1.220 + // XXX Option to import blocks as separate nodes? 1.221 + if (!DefaultLogger::isNullLogger()) { 1.222 + 1.223 + unsigned int vcount = 0, icount = 0; 1.224 + BOOST_FOREACH (const DXF::Block& bl, output.blocks) { 1.225 + BOOST_FOREACH (boost::shared_ptr<const DXF::PolyLine> pl, bl.lines) { 1.226 + vcount += pl->positions.size(); 1.227 + icount += pl->counts.size(); 1.228 + } 1.229 + } 1.230 + 1.231 + DefaultLogger::get()->debug((Formatter::format("DXF: Unexpanded polycount is "), 1.232 + icount,", vertex count is ",vcount 1.233 + )); 1.234 + } 1.235 + 1.236 + if (! output.blocks.size() ) { 1.237 + throw DeadlyImportError("DXF: no data blocks loaded"); 1.238 + } 1.239 + 1.240 + DXF::Block* entities = 0; 1.241 + 1.242 + // index blocks by name 1.243 + DXF::BlockMap blocks_by_name; 1.244 + BOOST_FOREACH (DXF::Block& bl, output.blocks) { 1.245 + blocks_by_name[bl.name] = &bl; 1.246 + if ( !entities && bl.name == AI_DXF_ENTITIES_MAGIC_BLOCK ) { 1.247 + entities = &bl; 1.248 + } 1.249 + } 1.250 + 1.251 + if (!entities) { 1.252 + throw DeadlyImportError("DXF: no ENTITIES data block loaded"); 1.253 + } 1.254 + 1.255 + typedef std::map<std::string, unsigned int> LayerMap; 1.256 + 1.257 + LayerMap layers; 1.258 + std::vector< std::vector< const DXF::PolyLine*> > corr; 1.259 + 1.260 + // now expand all block references in the primary ENTITIES block 1.261 + // XXX this involves heavy memory copying, consider a faster solution for future versions. 1.262 + ExpandBlockReferences(*entities,blocks_by_name); 1.263 + 1.264 + unsigned int cur = 0; 1.265 + BOOST_FOREACH (boost::shared_ptr<const DXF::PolyLine> pl, entities->lines) { 1.266 + if (pl->positions.size()) { 1.267 + 1.268 + std::map<std::string, unsigned int>::iterator it = layers.find(pl->layer); 1.269 + if (it == layers.end()) { 1.270 + ++pScene->mNumMeshes; 1.271 + 1.272 + layers[pl->layer] = cur++; 1.273 + 1.274 + std::vector< const DXF::PolyLine* > pv; 1.275 + pv.push_back(&*pl); 1.276 + 1.277 + corr.push_back(pv); 1.278 + } 1.279 + else { 1.280 + corr[(*it).second].push_back(&*pl); 1.281 + } 1.282 + } 1.283 + } 1.284 + 1.285 + if (!pScene->mNumMeshes) { 1.286 + throw DeadlyImportError("DXF: this file contains no 3d data"); 1.287 + } 1.288 + 1.289 + pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes ] (); 1.290 + 1.291 + BOOST_FOREACH(const LayerMap::value_type& elem, layers){ 1.292 + aiMesh* const mesh = pScene->mMeshes[elem.second] = new aiMesh(); 1.293 + mesh->mName.Set(elem.first); 1.294 + 1.295 + unsigned int cvert = 0,cface = 0; 1.296 + BOOST_FOREACH(const DXF::PolyLine* pl, corr[elem.second]){ 1.297 + // sum over all faces since we need to 'verbosify' them. 1.298 + cvert += std::accumulate(pl->counts.begin(),pl->counts.end(),0); 1.299 + cface += pl->counts.size(); 1.300 + } 1.301 + 1.302 + aiVector3D* verts = mesh->mVertices = new aiVector3D[cvert]; 1.303 + aiColor4D* colors = mesh->mColors[0] = new aiColor4D[cvert]; 1.304 + aiFace* faces = mesh->mFaces = new aiFace[cface]; 1.305 + 1.306 + mesh->mNumVertices = cvert; 1.307 + mesh->mNumFaces = cface; 1.308 + 1.309 + unsigned int prims = 0; 1.310 + unsigned int overall_indices = 0; 1.311 + BOOST_FOREACH(const DXF::PolyLine* pl, corr[elem.second]){ 1.312 + 1.313 + std::vector<unsigned int>::const_iterator it = pl->indices.begin(); 1.314 + BOOST_FOREACH(unsigned int facenumv,pl->counts) { 1.315 + aiFace& face = *faces++; 1.316 + face.mIndices = new unsigned int[face.mNumIndices = facenumv]; 1.317 + 1.318 + for (unsigned int i = 0; i < facenumv; ++i) { 1.319 + face.mIndices[i] = overall_indices++; 1.320 + 1.321 + ai_assert(pl->positions.size() == pl->colors.size()); 1.322 + if (*it >= pl->positions.size()) { 1.323 + throw DeadlyImportError("DXF: vertex index out of bounds"); 1.324 + } 1.325 + 1.326 + *verts++ = pl->positions[*it]; 1.327 + *colors++ = pl->colors[*it++]; 1.328 + } 1.329 + 1.330 + // set primitive flags now, this saves the extra pass in ScenePreprocessor. 1.331 + switch(face.mNumIndices) { 1.332 + case 1: 1.333 + prims |= aiPrimitiveType_POINT; 1.334 + break; 1.335 + case 2: 1.336 + prims |= aiPrimitiveType_LINE; 1.337 + break; 1.338 + case 3: 1.339 + prims |= aiPrimitiveType_TRIANGLE; 1.340 + break; 1.341 + default: 1.342 + prims |= aiPrimitiveType_POLYGON; 1.343 + break; 1.344 + } 1.345 + } 1.346 + } 1.347 + 1.348 + mesh->mPrimitiveTypes = prims; 1.349 + mesh->mMaterialIndex = 0; 1.350 + } 1.351 + 1.352 + GenerateHierarchy(pScene,output); 1.353 + GenerateMaterials(pScene,output); 1.354 +} 1.355 + 1.356 + 1.357 +// ------------------------------------------------------------------------------------------------ 1.358 +void DXFImporter::ExpandBlockReferences(DXF::Block& bl,const DXF::BlockMap& blocks_by_name) 1.359 +{ 1.360 + BOOST_FOREACH (const DXF::InsertBlock& insert, bl.insertions) { 1.361 + 1.362 + // first check if the referenced blocks exists ... 1.363 + const DXF::BlockMap::const_iterator it = blocks_by_name.find(insert.name); 1.364 + if (it == blocks_by_name.end()) { 1.365 + DefaultLogger::get()->error((Formatter::format("DXF: Failed to resolve block reference: "), 1.366 + insert.name,"; skipping" 1.367 + )); 1.368 + continue; 1.369 + } 1.370 + 1.371 + // XXX this would be the place to implement recursive expansion if needed. 1.372 + const DXF::Block& bl_src = *(*it).second; 1.373 + 1.374 + BOOST_FOREACH (boost::shared_ptr<const DXF::PolyLine> pl_in, bl_src.lines) { 1.375 + boost::shared_ptr<DXF::PolyLine> pl_out = boost::shared_ptr<DXF::PolyLine>(new DXF::PolyLine(*pl_in)); 1.376 + 1.377 + if (bl_src.base.Length() || insert.scale.x!=1.f || insert.scale.y!=1.f || insert.scale.z!=1.f || insert.angle || insert.pos.Length()) { 1.378 + // manual coordinate system transformation 1.379 + // XXX order 1.380 + aiMatrix4x4 trafo, tmp; 1.381 + aiMatrix4x4::Translation(-bl_src.base,trafo); 1.382 + trafo *= aiMatrix4x4::Scaling(insert.scale,tmp); 1.383 + trafo *= aiMatrix4x4::Translation(insert.pos,tmp); 1.384 + 1.385 + // XXX rotation currently ignored - I didn't find an appropriate sample model. 1.386 + if (insert.angle != 0.f) { 1.387 + DefaultLogger::get()->warn("DXF: BLOCK rotation not currently implemented"); 1.388 + } 1.389 + 1.390 + BOOST_FOREACH (aiVector3D& v, pl_out->positions) { 1.391 + v *= trafo; 1.392 + } 1.393 + } 1.394 + 1.395 + bl.lines.push_back(pl_out); 1.396 + } 1.397 + } 1.398 +} 1.399 + 1.400 + 1.401 +// ------------------------------------------------------------------------------------------------ 1.402 +void DXFImporter::GenerateMaterials(aiScene* pScene, DXF::FileData& /*output*/) 1.403 +{ 1.404 + // generate an almost-white default material. Reason: 1.405 + // the default vertex color is GREY, so we are 1.406 + // already at Assimp's usual default color. 1.407 + // generate a default material 1.408 + aiMaterial* pcMat = new aiMaterial(); 1.409 + aiString s; 1.410 + s.Set(AI_DEFAULT_MATERIAL_NAME); 1.411 + pcMat->AddProperty(&s, AI_MATKEY_NAME); 1.412 + 1.413 + aiColor4D clrDiffuse(0.9f,0.9f,0.9f,1.0f); 1.414 + pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_DIFFUSE); 1.415 + 1.416 + clrDiffuse = aiColor4D(1.0f,1.0f,1.0f,1.0f); 1.417 + pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_SPECULAR); 1.418 + 1.419 + clrDiffuse = aiColor4D(0.05f,0.05f,0.05f,1.0f); 1.420 + pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_AMBIENT); 1.421 + 1.422 + pScene->mNumMaterials = 1; 1.423 + pScene->mMaterials = new aiMaterial*[1]; 1.424 + pScene->mMaterials[0] = pcMat; 1.425 +} 1.426 + 1.427 + 1.428 +// ------------------------------------------------------------------------------------------------ 1.429 +void DXFImporter::GenerateHierarchy(aiScene* pScene, DXF::FileData& /*output*/) 1.430 +{ 1.431 + // generate the output scene graph, which is just the root node with a single child for each layer. 1.432 + pScene->mRootNode = new aiNode(); 1.433 + pScene->mRootNode->mName.Set("<DXF_ROOT>"); 1.434 + 1.435 + if (1 == pScene->mNumMeshes) { 1.436 + pScene->mRootNode->mMeshes = new unsigned int[ pScene->mRootNode->mNumMeshes = 1 ]; 1.437 + pScene->mRootNode->mMeshes[0] = 0; 1.438 + } 1.439 + else 1.440 + { 1.441 + pScene->mRootNode->mChildren = new aiNode*[ pScene->mRootNode->mNumChildren = pScene->mNumMeshes ]; 1.442 + for (unsigned int m = 0; m < pScene->mRootNode->mNumChildren;++m) { 1.443 + aiNode* p = pScene->mRootNode->mChildren[m] = new aiNode(); 1.444 + p->mName = pScene->mMeshes[m]->mName; 1.445 + 1.446 + p->mMeshes = new unsigned int[p->mNumMeshes = 1]; 1.447 + p->mMeshes[0] = m; 1.448 + p->mParent = pScene->mRootNode; 1.449 + } 1.450 + } 1.451 +} 1.452 + 1.453 + 1.454 +// ------------------------------------------------------------------------------------------------ 1.455 +void DXFImporter::SkipSection(DXF::LineReader& reader) 1.456 +{ 1.457 + for( ;!reader.End() && !reader.Is(0,"ENDSEC"); reader++); 1.458 +} 1.459 + 1.460 + 1.461 +// ------------------------------------------------------------------------------------------------ 1.462 +void DXFImporter::ParseHeader(DXF::LineReader& reader, DXF::FileData& /*output*/) 1.463 +{ 1.464 + for( ;!reader.End() && !reader.Is(0,"ENDSEC"); reader++); 1.465 +} 1.466 + 1.467 + 1.468 +// ------------------------------------------------------------------------------------------------ 1.469 +void DXFImporter::ParseBlocks(DXF::LineReader& reader, DXF::FileData& output) 1.470 +{ 1.471 + while( !reader.End() && !reader.Is(0,"ENDSEC")) { 1.472 + if (reader.Is(0,"BLOCK")) { 1.473 + ParseBlock(++reader,output); 1.474 + continue; 1.475 + } 1.476 + ++reader; 1.477 + } 1.478 + 1.479 + DefaultLogger::get()->debug((Formatter::format("DXF: got "), 1.480 + output.blocks.size()," entries in BLOCKS" 1.481 + )); 1.482 +} 1.483 + 1.484 + 1.485 +// ------------------------------------------------------------------------------------------------ 1.486 +void DXFImporter::ParseBlock(DXF::LineReader& reader, DXF::FileData& output) 1.487 +{ 1.488 + // push a new block onto the stack. 1.489 + output.blocks.push_back( DXF::Block() ); 1.490 + DXF::Block& block = output.blocks.back(); 1.491 + 1.492 + while( !reader.End() && !reader.Is(0,"ENDBLK")) { 1.493 + 1.494 + switch(reader.GroupCode()) { 1.495 + case 2: 1.496 + block.name = reader.Value(); 1.497 + break; 1.498 + 1.499 + case 10: 1.500 + block.base.x = reader.ValueAsFloat(); 1.501 + break; 1.502 + case 20: 1.503 + block.base.y = reader.ValueAsFloat(); 1.504 + break; 1.505 + case 30: 1.506 + block.base.z = reader.ValueAsFloat(); 1.507 + break; 1.508 + } 1.509 + 1.510 + if (reader.Is(0,"POLYLINE")) { 1.511 + ParsePolyLine(++reader,output); 1.512 + continue; 1.513 + } 1.514 + 1.515 + // XXX is this a valid case? 1.516 + if (reader.Is(0,"INSERT")) { 1.517 + DefaultLogger::get()->warn("DXF: INSERT within a BLOCK not currently supported; skipping"); 1.518 + for( ;!reader.End() && !reader.Is(0,"ENDBLK"); ++reader); 1.519 + break; 1.520 + } 1.521 + 1.522 + else if (reader.Is(0,"3DFACE") || reader.Is(0,"LINE") || reader.Is(0,"3DLINE")) { 1.523 + //http://sourceforge.net/tracker/index.php?func=detail&aid=2970566&group_id=226462&atid=1067632 1.524 + Parse3DFace(++reader, output); 1.525 + continue; 1.526 + } 1.527 + ++reader; 1.528 + } 1.529 +} 1.530 + 1.531 + 1.532 +// ------------------------------------------------------------------------------------------------ 1.533 +void DXFImporter::ParseEntities(DXF::LineReader& reader, DXF::FileData& output) 1.534 +{ 1.535 + // push a new block onto the stack. 1.536 + output.blocks.push_back( DXF::Block() ); 1.537 + DXF::Block& block = output.blocks.back(); 1.538 + 1.539 + block.name = AI_DXF_ENTITIES_MAGIC_BLOCK; 1.540 + 1.541 + while( !reader.End() && !reader.Is(0,"ENDSEC")) { 1.542 + if (reader.Is(0,"POLYLINE")) { 1.543 + ParsePolyLine(++reader,output); 1.544 + continue; 1.545 + } 1.546 + 1.547 + else if (reader.Is(0,"INSERT")) { 1.548 + ParseInsertion(++reader,output); 1.549 + continue; 1.550 + } 1.551 + 1.552 + else if (reader.Is(0,"3DFACE") || reader.Is(0,"LINE") || reader.Is(0,"3DLINE")) { 1.553 + //http://sourceforge.net/tracker/index.php?func=detail&aid=2970566&group_id=226462&atid=1067632 1.554 + Parse3DFace(++reader, output); 1.555 + continue; 1.556 + } 1.557 + 1.558 + ++reader; 1.559 + } 1.560 + 1.561 + DefaultLogger::get()->debug((Formatter::format("DXF: got "), 1.562 + block.lines.size()," polylines and ", block.insertions.size() ," inserted blocks in ENTITIES" 1.563 + )); 1.564 +} 1.565 + 1.566 + 1.567 +void DXFImporter::ParseInsertion(DXF::LineReader& reader, DXF::FileData& output) 1.568 +{ 1.569 + output.blocks.back().insertions.push_back( DXF::InsertBlock() ); 1.570 + DXF::InsertBlock& bl = output.blocks.back().insertions.back(); 1.571 + 1.572 + while( !reader.End() && !reader.Is(0)) { 1.573 + 1.574 + switch(reader.GroupCode()) 1.575 + { 1.576 + // name of referenced block 1.577 + case 2: 1.578 + bl.name = reader.Value(); 1.579 + break; 1.580 + 1.581 + // translation 1.582 + case 10: 1.583 + bl.pos.x = reader.ValueAsFloat(); 1.584 + break; 1.585 + case 20: 1.586 + bl.pos.y = reader.ValueAsFloat(); 1.587 + break; 1.588 + case 30: 1.589 + bl.pos.z = reader.ValueAsFloat(); 1.590 + break; 1.591 + 1.592 + // scaling 1.593 + case 41: 1.594 + bl.scale.x = reader.ValueAsFloat(); 1.595 + break; 1.596 + case 42: 1.597 + bl.scale.y = reader.ValueAsFloat(); 1.598 + break; 1.599 + case 43: 1.600 + bl.scale.z = reader.ValueAsFloat(); 1.601 + break; 1.602 + 1.603 + // rotation angle 1.604 + case 50: 1.605 + bl.angle = reader.ValueAsFloat(); 1.606 + break; 1.607 + } 1.608 + reader++; 1.609 + } 1.610 +} 1.611 + 1.612 +#define DXF_POLYLINE_FLAG_CLOSED 0x1 1.613 +#define DXF_POLYLINE_FLAG_3D_POLYLINE 0x8 1.614 +#define DXF_POLYLINE_FLAG_3D_POLYMESH 0x10 1.615 +#define DXF_POLYLINE_FLAG_POLYFACEMESH 0x40 1.616 + 1.617 +// ------------------------------------------------------------------------------------------------ 1.618 +void DXFImporter::ParsePolyLine(DXF::LineReader& reader, DXF::FileData& output) 1.619 +{ 1.620 + output.blocks.back().lines.push_back( boost::shared_ptr<DXF::PolyLine>( new DXF::PolyLine() ) ); 1.621 + DXF::PolyLine& line = *output.blocks.back().lines.back(); 1.622 + 1.623 + unsigned int iguess = 0, vguess = 0; 1.624 + while( !reader.End() && !reader.Is(0,"ENDSEC")) { 1.625 + 1.626 + if (reader.Is(0,"VERTEX")) { 1.627 + ParsePolyLineVertex(++reader,line); 1.628 + if (reader.Is(0,"SEQEND")) { 1.629 + break; 1.630 + } 1.631 + continue; 1.632 + } 1.633 + 1.634 + switch(reader.GroupCode()) 1.635 + { 1.636 + // flags --- important that we know whether it is a 1.637 + // polyface mesh or 'just' a line. 1.638 + case 70: 1.639 + if (!line.flags) { 1.640 + line.flags = reader.ValueAsSignedInt(); 1.641 + } 1.642 + break; 1.643 + 1.644 + // optional number of vertices 1.645 + case 71: 1.646 + vguess = reader.ValueAsSignedInt(); 1.647 + line.positions.reserve(vguess); 1.648 + break; 1.649 + 1.650 + // optional number of faces 1.651 + case 72: 1.652 + iguess = reader.ValueAsSignedInt(); 1.653 + line.indices.reserve(iguess); 1.654 + break; 1.655 + 1.656 + // 8 specifies the layer on which this line is placed on 1.657 + case 8: 1.658 + line.layer = reader.Value(); 1.659 + break; 1.660 + } 1.661 + 1.662 + reader++; 1.663 + } 1.664 + 1.665 + //if (!(line.flags & DXF_POLYLINE_FLAG_POLYFACEMESH)) { 1.666 + // DefaultLogger::get()->warn((Formatter::format("DXF: polyline not currently supported: "),line.flags)); 1.667 + // output.blocks.back().lines.pop_back(); 1.668 + // return; 1.669 + //} 1.670 + 1.671 + if (vguess && line.positions.size() != vguess) { 1.672 + DefaultLogger::get()->warn((Formatter::format("DXF: unexpected vertex count in polymesh: "), 1.673 + line.positions.size(),", expected ", vguess 1.674 + )); 1.675 + } 1.676 + 1.677 + if (line.flags & DXF_POLYLINE_FLAG_POLYFACEMESH ) { 1.678 + if (line.positions.size() < 3 || line.indices.size() < 3) { 1.679 + DefaultLogger::get()->warn("DXF: not enough vertices for polymesh; ignoring"); 1.680 + output.blocks.back().lines.pop_back(); 1.681 + return; 1.682 + } 1.683 + 1.684 + // if these numbers are wrong, parsing might have gone wild. 1.685 + // however, the docs state that applications are not required 1.686 + // to set the 71 and 72 fields, respectively, to valid values. 1.687 + // So just fire a warning. 1.688 + if (iguess && line.counts.size() != iguess) { 1.689 + DefaultLogger::get()->warn((Formatter::format("DXF: unexpected face count in polymesh: "), 1.690 + line.counts.size(),", expected ", iguess 1.691 + )); 1.692 + } 1.693 + } 1.694 + else if (!line.indices.size() && !line.counts.size()) { 1.695 + // a polyline - so there are no indices yet. 1.696 + size_t guess = line.positions.size() + (line.flags & DXF_POLYLINE_FLAG_CLOSED ? 1 : 0); 1.697 + line.indices.reserve(guess); 1.698 + 1.699 + line.counts.reserve(guess/2); 1.700 + for (unsigned int i = 0; i < line.positions.size()/2; ++i) { 1.701 + line.indices.push_back(i*2); 1.702 + line.indices.push_back(i*2+1); 1.703 + line.counts.push_back(2); 1.704 + } 1.705 + 1.706 + // closed polyline? 1.707 + if (line.flags & DXF_POLYLINE_FLAG_CLOSED) { 1.708 + line.indices.push_back(line.positions.size()-1); 1.709 + line.indices.push_back(0); 1.710 + line.counts.push_back(2); 1.711 + } 1.712 + } 1.713 +} 1.714 + 1.715 +#define DXF_VERTEX_FLAG_PART_OF_POLYFACE 0x80 1.716 +#define DXF_VERTEX_FLAG_HAS_POSITIONS 0x40 1.717 + 1.718 +// ------------------------------------------------------------------------------------------------ 1.719 +void DXFImporter::ParsePolyLineVertex(DXF::LineReader& reader, DXF::PolyLine& line) 1.720 +{ 1.721 + unsigned int cnti = 0, flags = 0; 1.722 + unsigned int indices[4]; 1.723 + 1.724 + aiVector3D out; 1.725 + aiColor4D clr = AI_DXF_DEFAULT_COLOR; 1.726 + 1.727 + while( !reader.End() ) { 1.728 + 1.729 + if (reader.Is(0)) { // SEQEND or another VERTEX 1.730 + break; 1.731 + } 1.732 + 1.733 + switch (reader.GroupCode()) 1.734 + { 1.735 + case 8: 1.736 + // layer to which the vertex belongs to - assume that 1.737 + // this is always the layer the top-level polyline 1.738 + // entity resides on as well. 1.739 + if(reader.Value() != line.layer) { 1.740 + DefaultLogger::get()->warn("DXF: expected vertex to be part of a polyface but the 0x128 flag isn't set"); 1.741 + } 1.742 + break; 1.743 + 1.744 + case 70: 1.745 + flags = reader.ValueAsUnsignedInt(); 1.746 + break; 1.747 + 1.748 + // VERTEX COORDINATES 1.749 + case 10: out.x = reader.ValueAsFloat();break; 1.750 + case 20: out.y = reader.ValueAsFloat();break; 1.751 + case 30: out.z = reader.ValueAsFloat();break; 1.752 + 1.753 + // POLYFACE vertex indices 1.754 + case 71: 1.755 + case 72: 1.756 + case 73: 1.757 + case 74: 1.758 + if (cnti == 4) { 1.759 + DefaultLogger::get()->warn("DXF: more than 4 indices per face not supported; ignoring"); 1.760 + break; 1.761 + } 1.762 + indices[cnti++] = reader.ValueAsUnsignedInt(); 1.763 + break; 1.764 + 1.765 + // color 1.766 + case 62: 1.767 + clr = g_aclrDxfIndexColors[reader.ValueAsUnsignedInt() % AI_DXF_NUM_INDEX_COLORS]; 1.768 + break; 1.769 + }; 1.770 + 1.771 + reader++; 1.772 + } 1.773 + 1.774 + if (line.flags & DXF_POLYLINE_FLAG_POLYFACEMESH && !(flags & DXF_VERTEX_FLAG_PART_OF_POLYFACE)) { 1.775 + DefaultLogger::get()->warn("DXF: expected vertex to be part of a polyface but the 0x128 flag isn't set"); 1.776 + } 1.777 + 1.778 + if (cnti) { 1.779 + line.counts.push_back(cnti); 1.780 + for (unsigned int i = 0; i < cnti; ++i) { 1.781 + // IMPORTANT NOTE: POLYMESH indices are ONE-BASED 1.782 + if (indices[i] == 0) { 1.783 + DefaultLogger::get()->warn("DXF: invalid vertex index, indices are one-based."); 1.784 + --line.counts.back(); 1.785 + continue; 1.786 + } 1.787 + line.indices.push_back(indices[i]-1); 1.788 + } 1.789 + } 1.790 + else { 1.791 + line.positions.push_back(out); 1.792 + line.colors.push_back(clr); 1.793 + } 1.794 +} 1.795 + 1.796 +// ------------------------------------------------------------------------------------------------ 1.797 +void DXFImporter::Parse3DFace(DXF::LineReader& reader, DXF::FileData& output) 1.798 +{ 1.799 + // (note) this is also used for for parsing line entities, so we 1.800 + // must handle the vertex_count == 2 case as well. 1.801 + 1.802 + output.blocks.back().lines.push_back( boost::shared_ptr<DXF::PolyLine>( new DXF::PolyLine() ) ); 1.803 + DXF::PolyLine& line = *output.blocks.back().lines.back(); 1.804 + 1.805 + aiVector3D vip[4]; 1.806 + aiColor4D clr = AI_DXF_DEFAULT_COLOR; 1.807 + 1.808 + bool b[4] = {false,false,false,false}; 1.809 + while( !reader.End() ) { 1.810 + 1.811 + // next entity with a groupcode == 0 is probably already the next vertex or polymesh entity 1.812 + if (reader.GroupCode() == 0) { 1.813 + break; 1.814 + } 1.815 + switch (reader.GroupCode()) 1.816 + { 1.817 + 1.818 + // 8 specifies the layer 1.819 + case 8: 1.820 + line.layer = reader.Value(); 1.821 + break; 1.822 + 1.823 + // x position of the first corner 1.824 + case 10: vip[0].x = reader.ValueAsFloat(); 1.825 + b[2] = true; 1.826 + break; 1.827 + 1.828 + // y position of the first corner 1.829 + case 20: vip[0].y = reader.ValueAsFloat(); 1.830 + b[2] = true; 1.831 + break; 1.832 + 1.833 + // z position of the first corner 1.834 + case 30: vip[0].z = reader.ValueAsFloat(); 1.835 + b[2] = true; 1.836 + break; 1.837 + 1.838 + // x position of the second corner 1.839 + case 11: vip[1].x = reader.ValueAsFloat(); 1.840 + b[3] = true; 1.841 + break; 1.842 + 1.843 + // y position of the second corner 1.844 + case 21: vip[1].y = reader.ValueAsFloat(); 1.845 + b[3] = true; 1.846 + break; 1.847 + 1.848 + // z position of the second corner 1.849 + case 31: vip[1].z = reader.ValueAsFloat(); 1.850 + b[3] = true; 1.851 + break; 1.852 + 1.853 + // x position of the third corner 1.854 + case 12: vip[2].x = reader.ValueAsFloat(); 1.855 + b[0] = true; 1.856 + break; 1.857 + 1.858 + // y position of the third corner 1.859 + case 22: vip[2].y = reader.ValueAsFloat(); 1.860 + b[0] = true; 1.861 + break; 1.862 + 1.863 + // z position of the third corner 1.864 + case 32: vip[2].z = reader.ValueAsFloat(); 1.865 + b[0] = true; 1.866 + break; 1.867 + 1.868 + // x position of the fourth corner 1.869 + case 13: vip[3].x = reader.ValueAsFloat(); 1.870 + b[1] = true; 1.871 + break; 1.872 + 1.873 + // y position of the fourth corner 1.874 + case 23: vip[3].y = reader.ValueAsFloat(); 1.875 + b[1] = true; 1.876 + break; 1.877 + 1.878 + // z position of the fourth corner 1.879 + case 33: vip[3].z = reader.ValueAsFloat(); 1.880 + b[1] = true; 1.881 + break; 1.882 + 1.883 + // color 1.884 + case 62: 1.885 + clr = g_aclrDxfIndexColors[reader.ValueAsUnsignedInt() % AI_DXF_NUM_INDEX_COLORS]; 1.886 + break; 1.887 + }; 1.888 + 1.889 + ++reader; 1.890 + } 1.891 + 1.892 + // the fourth corner may even be identical to the third, 1.893 + // in this case we treat it as if it didn't exist. 1.894 + if (vip[3] == vip[2]) { 1.895 + b[1] = false; 1.896 + } 1.897 + 1.898 + // sanity checks to see if we got something meaningful 1.899 + if ((b[1] && !b[0]) || !b[2] || !b[3]) { 1.900 + DefaultLogger::get()->warn("DXF: unexpected vertex setup in 3DFACE/LINE/FACE entity; ignoring"); 1.901 + output.blocks.back().lines.pop_back(); 1.902 + return; 1.903 + } 1.904 + 1.905 + const unsigned int cnt = (2+(b[0]?1:0)+(b[1]?1:0)); 1.906 + line.counts.push_back(cnt); 1.907 + 1.908 + for (unsigned int i = 0; i < cnt; ++i) { 1.909 + line.indices.push_back(line.positions.size()); 1.910 + line.positions.push_back(vip[i]); 1.911 + line.colors.push_back(clr); 1.912 + } 1.913 +} 1.914 + 1.915 +#endif // !! ASSIMP_BUILD_NO_DXF_IMPORTER 1.916 +