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 +