static int scalar_cb(p_ply_argument argument) { CCLib::ScalarField* sf = 0; ply_get_argument_user_data(argument, (void**)(&sf), NULL); p_ply_element element; long instance_index; ply_get_argument_element(argument, &element, &instance_index); ScalarType scal = static_cast<ScalarType>(ply_get_argument_value(argument)); sf->setValue(instance_index,scal); if ((++s_totalScalarCount % PROCESS_EVENTS_FREQ) == 0) QCoreApplication::processEvents(); return 1; }
CC_FILE_ERROR BinFilter::LoadFileV1(QFile& in, ccHObject& container, unsigned nbScansTotal, const LoadParameters& parameters) { ccLog::Print("[BIN] Version 1.0"); if (nbScansTotal > 99) { if (QMessageBox::question(0, QString("Oups"), QString("Hum, do you really expect %1 point clouds?").arg(nbScansTotal), QMessageBox::Yes, QMessageBox::No) == QMessageBox::No) return CC_FERR_WRONG_FILE_TYPE; } else if (nbScansTotal == 0) { return CC_FERR_NO_LOAD; } ccProgressDialog pdlg(true, parameters.parentWidget); pdlg.setMethodTitle(QObject::tr("Open Bin file (old style)")); for (unsigned k=0; k<nbScansTotal; k++) { HeaderFlags header; unsigned nbOfPoints = 0; if (ReadEntityHeader(in, nbOfPoints, header) < 0) { return CC_FERR_READING; } //Console::print("[BinFilter::loadModelFromBinaryFile] Entity %i : %i points, color=%i, norms=%i, dists=%i\n",k,nbOfPoints,color,norms,distances); if (nbOfPoints == 0) { //Console::print("[BinFilter::loadModelFromBinaryFile] rien a faire !\n"); continue; } //progress for this cloud CCLib::NormalizedProgress nprogress(&pdlg, nbOfPoints); if (parameters.alwaysDisplayLoadDialog) { pdlg.reset(); pdlg.setInfo(QObject::tr("cloud %1/%2 (%3 points)").arg(k + 1).arg(nbScansTotal).arg(nbOfPoints)); pdlg.start(); QApplication::processEvents(); } //Cloud name char cloudName[256] = "unnamed"; if (header.name) { for (int i=0; i<256; ++i) { if (in.read(cloudName+i,1) < 0) { //Console::print("[BinFilter::loadModelFromBinaryFile] Error reading the cloud name!\n"); return CC_FERR_READING; } if (cloudName[i] == 0) { break; } } //we force the end of the name in case it is too long! cloudName[255] = 0; } else { sprintf(cloudName,"unnamed - Cloud #%u",k); } //Cloud name char sfName[1024] = "unnamed"; if (header.sfName) { for (int i=0; i<1024; ++i) { if (in.read(sfName+i,1) < 0) { //Console::print("[BinFilter::loadModelFromBinaryFile] Error reading the cloud name!\n"); return CC_FERR_READING; } if (sfName[i] == 0) break; } //we force the end of the name in case it is too long! sfName[1023] = 0; } else { strcpy(sfName,"Loaded scalar field"); } //Creation ccPointCloud* loadedCloud = new ccPointCloud(cloudName); if (!loadedCloud) return CC_FERR_NOT_ENOUGH_MEMORY; unsigned fileChunkPos = 0; unsigned fileChunkSize = std::min(nbOfPoints,CC_MAX_NUMBER_OF_POINTS_PER_CLOUD); loadedCloud->reserveThePointsTable(fileChunkSize); if (header.colors) { loadedCloud->reserveTheRGBTable(); loadedCloud->showColors(true); } if (header.normals) { loadedCloud->reserveTheNormsTable(); loadedCloud->showNormals(true); } if (header.scalarField) loadedCloud->enableScalarField(); unsigned lineRead = 0; int parts = 0; const ScalarType FORMER_HIDDEN_POINTS = (ScalarType)-1.0; //lecture du fichier for (unsigned i=0; i<nbOfPoints; ++i) { if (lineRead == fileChunkPos+fileChunkSize) { if (header.scalarField) loadedCloud->getCurrentInScalarField()->computeMinAndMax(); container.addChild(loadedCloud); fileChunkPos = lineRead; fileChunkSize = std::min(nbOfPoints-lineRead,CC_MAX_NUMBER_OF_POINTS_PER_CLOUD); char partName[64]; ++parts; sprintf(partName,"%s.part_%i",cloudName,parts); loadedCloud = new ccPointCloud(partName); loadedCloud->reserveThePointsTable(fileChunkSize); if (header.colors) { loadedCloud->reserveTheRGBTable(); loadedCloud->showColors(true); } if (header.normals) { loadedCloud->reserveTheNormsTable(); loadedCloud->showNormals(true); } if (header.scalarField) loadedCloud->enableScalarField(); } float Pf[3]; if (in.read((char*)Pf,sizeof(float)*3) < 0) { //Console::print("[BinFilter::loadModelFromBinaryFile] Error reading the %ith entity point !\n",k); return CC_FERR_READING; } loadedCloud->addPoint(CCVector3::fromArray(Pf)); if (header.colors) { unsigned char C[3]; if (in.read((char*)C,sizeof(ColorCompType)*3) < 0) { //Console::print("[BinFilter::loadModelFromBinaryFile] Error reading the %ith entity colors !\n",k); return CC_FERR_READING; } loadedCloud->addRGBColor(C); } if (header.normals) { CCVector3 N; if (in.read((char*)N.u,sizeof(float)*3) < 0) { //Console::print("[BinFilter::loadModelFromBinaryFile] Error reading the %ith entity norms !\n",k); return CC_FERR_READING; } loadedCloud->addNorm(N); } if (header.scalarField) { double D; if (in.read((char*)&D,sizeof(double)) < 0) { //Console::print("[BinFilter::loadModelFromBinaryFile] Error reading the %ith entity distance!\n",k); return CC_FERR_READING; } ScalarType d = static_cast<ScalarType>(D); loadedCloud->setPointScalarValue(i,d); } lineRead++; if (parameters.alwaysDisplayLoadDialog && !nprogress.oneStep()) { loadedCloud->resize(i+1-fileChunkPos); k=nbScansTotal; i=nbOfPoints; } } if (parameters.alwaysDisplayLoadDialog) { pdlg.stop(); QApplication::processEvents(); } if (header.scalarField) { CCLib::ScalarField* sf = loadedCloud->getCurrentInScalarField(); assert(sf); sf->setName(sfName); //replace HIDDEN_VALUES by NAN_VALUES for (unsigned i=0; i<sf->currentSize(); ++i) { if (sf->getValue(i) == FORMER_HIDDEN_POINTS) sf->setValue(i,NAN_VALUE); } sf->computeMinAndMax(); loadedCloud->setCurrentDisplayedScalarField(loadedCloud->getCurrentInScalarFieldIndex()); loadedCloud->showSF(true); } container.addChild(loadedCloud); } return CC_FERR_NO_ERROR; }
ccPointCloud* cc2Point5DimEditor::convertGridToCloud( const std::vector<ExportableFields>& exportedFields, bool interpolateSF, bool resampleInputCloud, ccGenericPointCloud* inputCloud, bool fillEmptyCells, double emptyCellsHeight) const { if (!m_grid.isValid()) return 0; unsigned pointsCount = (fillEmptyCells ? m_grid.width * m_grid.height : m_grid.validCellCount); if (pointsCount == 0) { ccLog::Warning("[Rasterize] Empty grid!"); return 0; } ccPointCloud* cloudGrid = 0; if (resampleInputCloud) { CCLib::ReferenceCloud refCloud(inputCloud); if (refCloud.reserve(m_grid.nonEmptyCellCount)) { for (unsigned j=0; j<m_grid.height; ++j) { for (unsigned i=0; i<m_grid.width; ++i) { const RasterCell& cell = m_grid.data[j][i]; if (cell.nbPoints) //non empty cell { refCloud.addPointIndex(cell.pointIndex); } } } assert(refCloud.size() != 0); cloudGrid = inputCloud->isA(CC_TYPES::POINT_CLOUD) ? static_cast<ccPointCloud*>(inputCloud)->partialClone(&refCloud) : ccPointCloud::From(&refCloud,inputCloud); cloudGrid->setPointSize(0); //to avoid display issues //even if we have already resampled the original cloud we may have to create new points and/or scalar fields //if (!interpolateSF && !fillEmptyCells) // return cloudGrid; } else { ccLog::Warning("[Rasterize] Not enough memory!"); return 0; } } else { cloudGrid = new ccPointCloud("grid"); } assert(cloudGrid); //shall we generate per-cell fields as well? std::vector<CCLib::ScalarField*> exportedSFs; if (!exportedFields.empty()) { exportedSFs.resize(exportedFields.size(),0); for (size_t i=0; i<exportedFields.size(); ++i) { int sfIndex = -1; switch (exportedFields[i]) { case PER_CELL_HEIGHT: case PER_CELL_COUNT: case PER_CELL_MIN_HEIGHT: case PER_CELL_MAX_HEIGHT: case PER_CELL_AVG_HEIGHT: case PER_CELL_HEIGHT_STD_DEV: case PER_CELL_HEIGHT_RANGE: sfIndex = cloudGrid->addScalarField(qPrintable(GetDefaultFieldName(exportedFields[i]))); break; default: assert(false); break; } if (sfIndex < 0) { ccLog::Warning("[Rasterize] Couldn't allocate scalar field(s)! Try to free some memory ..."); break; } exportedSFs[i] = cloudGrid->getScalarField(sfIndex); assert(exportedSFs[i]); } } //the resampled cloud already contains the points corresponding to 'filled' cells so we will only //need to add the empty ones (if requested) if ((!resampleInputCloud || fillEmptyCells) && !cloudGrid->reserve(pointsCount)) { ccLog::Warning("[Rasterize] Not enough memory!"); delete cloudGrid; return 0; } //vertical dimension const unsigned char Z = getProjectionDimension(); assert(Z >= 0 && Z <= 2); const unsigned char X = Z == 2 ? 0 : Z +1; const unsigned char Y = X == 2 ? 0 : X +1; //cloud bounding-box ccBBox box = getCustomBBox(); assert(box.isValid()); //we work with doubles as grid step can be much smaller than the cloud coordinates! double Py = box.minCorner().u[Y]; //as the 'non empty cells points' are already in the cloud //we must take care of where we put the scalar fields values! unsigned nonEmptyCellIndex = 0; for (unsigned j=0; j<m_grid.height; ++j) { const RasterCell* aCell = m_grid.data[j]; double Px = box.minCorner().u[X]; for (unsigned i=0; i<m_grid.width; ++i,++aCell) { if (aCell->h == aCell->h) //valid cell { //if we haven't resampled the original cloud, we must add the point //corresponding to this non-empty cell if (!resampleInputCloud || aCell->nbPoints == 0) { CCVector3 Pf( static_cast<PointCoordinateType>(Px), static_cast<PointCoordinateType>(Py), static_cast<PointCoordinateType>(aCell->h) ); cloudGrid->addPoint(Pf); } //fill the associated SFs assert(exportedSFs.size() >= exportedFields.size()); assert(!inputCloud || nonEmptyCellIndex < inputCloud->size()); for (size_t i=0; i<exportedSFs.size(); ++i) { CCLib::ScalarField* sf = exportedSFs[i]; ScalarType sVal = NAN_VALUE; switch (exportedFields[i]) { case PER_CELL_HEIGHT: sVal = static_cast<ScalarType>(aCell->h); break; case PER_CELL_COUNT: sVal = static_cast<ScalarType>(aCell->nbPoints); break; case PER_CELL_MIN_HEIGHT: sVal = static_cast<ScalarType>(aCell->minHeight); break; case PER_CELL_MAX_HEIGHT: sVal = static_cast<ScalarType>(aCell->maxHeight); break; case PER_CELL_AVG_HEIGHT: sVal = static_cast<ScalarType>(aCell->avgHeight); break; case PER_CELL_HEIGHT_STD_DEV: sVal = static_cast<ScalarType>(aCell->stdDevHeight); break; case PER_CELL_HEIGHT_RANGE: sVal = static_cast<ScalarType>(aCell->maxHeight - aCell->minHeight); break; default: assert(false); break; } if (resampleInputCloud) sf->setValue(nonEmptyCellIndex,sVal); else sf->addElement(sVal); } ++nonEmptyCellIndex; } else if (fillEmptyCells) //empty cell { //even if we have resampled the original cloud, we must add the point //corresponding to this empty cell { CCVector3 Pf( static_cast<PointCoordinateType>(Px), static_cast<PointCoordinateType>(Py), static_cast<PointCoordinateType>(emptyCellsHeight) ); cloudGrid->addPoint(Pf); } assert(exportedSFs.size() == exportedFields.size()); for (size_t i=0; i<exportedSFs.size(); ++i) { if (!exportedSFs[i]) { continue; } if (exportedFields[i] == PER_CELL_HEIGHT) { //we set the point height to the default height ScalarType s = static_cast<ScalarType>(emptyCellsHeight); exportedSFs[i]->addElement(s); } else { exportedSFs[i]->addElement(NAN_VALUE); } } } Px += m_grid.gridStep; } Py += m_grid.gridStep; } assert(exportedSFs.size() == exportedFields.size()); for (size_t i=0; i<exportedSFs.size(); ++i) { CCLib::ScalarField* sf = exportedSFs[i]; if (sf) { sf->computeMinAndMax(); } } //take care of former scalar fields if (!resampleInputCloud) { if (interpolateSF && inputCloud && inputCloud->isA(CC_TYPES::POINT_CLOUD)) { ccPointCloud* pc = static_cast<ccPointCloud*>(inputCloud); for (size_t k=0; k<m_grid.scalarFields.size(); ++k) { double* _sfGrid = m_grid.scalarFields[k]; if (_sfGrid) //valid SF grid { //the corresponding SF should exist on the input cloud ccScalarField* formerSf = static_cast<ccScalarField*>(pc->getScalarField(static_cast<int>(k))); assert(formerSf); //we try to create an equivalent SF on the output grid int sfIdx = cloudGrid->addScalarField(formerSf->getName()); if (sfIdx < 0) //if we aren't lucky, the input cloud already had a SF with CC_HEIGHT_GRID_FIELD_NAME as name sfIdx = cloudGrid->addScalarField(qPrintable(QString(formerSf->getName()).append(".old"))); if (sfIdx < 0) { ccLog::Warning("[Rasterize] Couldn't allocate a new scalar field for storing SF '%s' values! Try to free some memory ...",formerSf->getName()); } else { ccScalarField* sf = static_cast<ccScalarField*>(cloudGrid->getScalarField(sfIdx)); assert(sf); //set sf values unsigned n = 0; const ScalarType emptyCellSFValue = CCLib::ScalarField::NaN(); for (unsigned j=0; j<m_grid.height; ++j) { const RasterCell* aCell = m_grid.data[j]; for (unsigned i=0; i<m_grid.width; ++i, ++_sfGrid, ++aCell) { if (aCell->nbPoints) { ScalarType s = static_cast<ScalarType>(*_sfGrid); sf->setValue(n++,s); } else if (fillEmptyCells) { sf->setValue(n++,emptyCellSFValue); } } } sf->computeMinAndMax(); sf->importParametersFrom(formerSf); assert(sf->currentSize() == pointsCount); } } } } } else { for (size_t k=0; k<cloudGrid->getNumberOfScalarFields(); ++k) { CCLib::ScalarField* sf = cloudGrid->getScalarField(static_cast<int>(k)); sf->resize(cloudGrid->size(),true,NAN_VALUE); } } QString gridName = QString("raster(%1)").arg(m_grid.gridStep); if (inputCloud) { gridName.prepend(inputCloud->getName() + QString(".")); } cloudGrid->setName(gridName); return cloudGrid; }
CC_FILE_ERROR VTKFilter::loadFile(const char* filename, ccHObject& container, bool alwaysDisplayLoadDialog/*=true*/, bool* coordinatesShiftEnabled/*=0*/, CCVector3d* coordinatesShift/*=0*/) { //open ASCII file for reading QFile file(filename); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) return CC_FERR_READING; QTextStream inFile(&file); //read header QString nextline = inFile.readLine(); if (!nextline.startsWith("# vtk")) return CC_FERR_MALFORMED_FILE; //comment nextline = inFile.readLine(); ccLog::Print(QString("[VTK] ")+nextline); ccMesh* mesh = 0; ccPointCloud* vertices = 0; std::vector<int> indexes; //global so as to avoid unnecessary mem. allocations QString lastSfName; bool acceptLookupTables = true; QString fileType = inFile.readLine().toUpper(); if (fileType.startsWith("BINARY")) { //binary not supported yet! ccLog::Error("VTK binary format not supported yet!"); return CC_FERR_WRONG_FILE_TYPE; } else if (fileType.startsWith("ASCII")) { //allow blank lines QString dataType; if (!GetNextNonEmptyLine(inFile,dataType)) return CC_FERR_MALFORMED_FILE; if (!dataType.startsWith("DATASET")) return CC_FERR_MALFORMED_FILE; dataType.remove(0,8); if (dataType.startsWith("POLYDATA")) { vertices = new ccPointCloud("vertices"); mesh = new ccMesh(vertices); } else if (dataType.startsWith("UNSTRUCTURED_GRID")) { vertices = new ccPointCloud("unnamed - VTK unstructured grid"); } else { ccLog::Error(QString("VTK entity '%1' is not supported!").arg(dataType)); return CC_FERR_WRONG_FILE_TYPE; } } //loop on keywords/data CC_FILE_ERROR error = CC_FERR_NO_ERROR; CCVector3d Pshift(0,0,0); while (error == CC_FERR_NO_ERROR) { if (!GetNextNonEmptyLine(inFile,nextline)) break; //end of file assert(!nextline.isEmpty()); if (nextline.startsWith("POINTS")) { QStringList parts = nextline.split(" ",QString::SkipEmptyParts); if (parts.size() != 3) { error=CC_FERR_MALFORMED_FILE; break; } bool ok = false; unsigned ptsCount = parts[1].toInt(&ok); if (!ok) { error = CC_FERR_MALFORMED_FILE; break; } //QString dataFormat = parts[3].toUpper(); //char buffer[8]; //unsigned char datSize = 4; //if (dataFormat == "DOUBLE") //{ // datSize = 8; //} //else if (dataFormat != "FLOAT") //{ // ccLog::Error(QString("Non floating point data (%1) is not supported!").arg(dataFormat)); // error = CC_FERR_WRONG_FILE_TYPE; // break; //} if (!vertices->reserve(ptsCount)) { error = CC_FERR_NOT_ENOUGH_MEMORY; break; } for (unsigned i=0; i<ptsCount; ++i) { nextline = inFile.readLine(); parts = nextline.split(" ",QString::SkipEmptyParts); if (parts.size() != 3) { error = CC_FERR_MALFORMED_FILE; break; } double Pd[3] = {0,0,0}; for (unsigned char j=0; j<3; ++j) { Pd[j] = parts[j].toDouble(&ok); if (!ok) { ccLog::Warning("[VTK] Element #%1 of POINTS data is corrupted!",i); error = CC_FERR_MALFORMED_FILE; break; } } //first point: check for 'big' coordinates if (i == 0) { bool shiftAlreadyEnabled = (coordinatesShiftEnabled && *coordinatesShiftEnabled && coordinatesShift); if (shiftAlreadyEnabled) Pshift = *coordinatesShift; bool applyAll = false; if ( sizeof(PointCoordinateType) < 8 && ccCoordinatesShiftManager::Handle(Pd,0,alwaysDisplayLoadDialog,shiftAlreadyEnabled,Pshift,0,applyAll)) { vertices->setGlobalShift(Pshift); ccLog::Warning("[VTKFilter::loadFile] Cloud has been recentered! Translation: (%.2f,%.2f,%.2f)",Pshift.x,Pshift.y,Pshift.z); //we save coordinates shift information if (applyAll && coordinatesShiftEnabled && coordinatesShift) { *coordinatesShiftEnabled = true; *coordinatesShift = Pshift; } } } vertices->addPoint(CCVector3( static_cast<PointCoordinateType>(Pd[0] + Pshift.x), static_cast<PointCoordinateType>(Pd[1] + Pshift.y), static_cast<PointCoordinateType>(Pd[2] + Pshift.z)) ); } //end POINTS } else if (nextline.startsWith("POLYGONS") || nextline.startsWith("TRIANGLE_STRIPS")) { QStringList parts = nextline.split(" ",QString::SkipEmptyParts); if (parts.size() != 3) { error = CC_FERR_MALFORMED_FILE; break; } //current type name (i.e. POLYGONS or TRIANGLE_STRIPS) QString typeName = parts[0]; bool isPolygon = (typeName == "POLYGONS"); bool ok = false; unsigned elemCount = parts[1].toUInt(&ok); if (!ok) { error = CC_FERR_MALFORMED_FILE; break; } unsigned totalElements = parts[2].toUInt(&ok); if (!ok) { error = CC_FERR_MALFORMED_FILE; break; } assert(mesh); if (!mesh) { ccLog::Warning(QString("[VTK] We found %1 data while file is not composed of POLYDATA!").arg(typeName)); mesh = new ccMesh(vertices); //however, we can still try to load it? } for (unsigned i=0; i<elemCount; ++i) { nextline = inFile.readLine(); parts = nextline.split(" ",QString::SkipEmptyParts); if (parts.empty()) { error = CC_FERR_MALFORMED_FILE; break; } unsigned vertCount = parts[0].toUInt(&ok); if (!ok || static_cast<int>(vertCount) >= parts.size()) { error = CC_FERR_MALFORMED_FILE; break; } else if (vertCount < 3) { ccLog::Warning(QString("[VTK] Element #%1 of %2 data is corrupted! (not enough indexes)").arg(i).arg(typeName)); } if (isPolygon && (vertCount != 3 && vertCount != 4)) //quads are easy to handle as well! { ccLog::Warning(QString("[VTK] POLYGON element #%1 has an unhandled size (> 4 vertices)").arg(i)); continue; } //reserve mem to. store indexes if (indexes.size() < vertCount) { try { indexes.resize(vertCount); } catch (std::bad_alloc) { error = CC_FERR_NOT_ENOUGH_MEMORY; break; } } //decode indexes for (unsigned j=0; j<vertCount; ++j) { indexes[j] = parts[j+1].toUInt(&ok); if (!ok) { ccLog::Warning(QString("[VTK] Element #%1 of %2 data is corrupted! (invalid index value)").arg(i).arg(typeName)); error = CC_FERR_MALFORMED_FILE; break; } } //add the triangles { assert(vertCount > 2); unsigned triCount = vertCount-2; if (mesh->size() + triCount > mesh->maxSize()) { if (!mesh->reserve(mesh->size()+triCount+256)) //take some advance to avoid too many allocations { error = CC_FERR_NOT_ENOUGH_MEMORY; break; } } if (isPolygon) { //triangle or quad mesh->addTriangle(indexes[0],indexes[1],indexes[2]); if (vertCount == 4) mesh->addTriangle(indexes[0],indexes[2],indexes[3]); } else { //triangle strip for (unsigned j=0; j<triCount; ++j) mesh->addTriangle(indexes[j],indexes[j+1],indexes[j+2]); } } } if (mesh->size() != 0 && mesh->size() < mesh->maxSize()) { mesh->resize(mesh->size()); } //end POLYGONS or TRIANGLE_STRIPS } else if (nextline.startsWith("NORMALS")) { unsigned ptsCount = vertices->size(); if (vertices->size() == 0) { error = CC_FERR_MALFORMED_FILE; break; } else { bool loadNormals = vertices->reserveTheNormsTable(); if (!loadNormals) ccLog::Warning("[VTK] Not enough memory to load normals!"); for (unsigned i=0; i<ptsCount; ++i) { nextline = inFile.readLine(); if (loadNormals) { QStringList parts = nextline.split(" ",QString::SkipEmptyParts); if (parts.size() != 3) { error = CC_FERR_MALFORMED_FILE; break; } CCVector3 N; for (unsigned char j=0; j<3; ++j) { bool ok; N.u[j] = (PointCoordinateType)parts[j].toDouble(&ok); if (!ok) { ccLog::Warning("[VTK] Element #%1 of NORMALS data is corrupted!",i); error = CC_FERR_MALFORMED_FILE; break; } } vertices->addNorm(N); } } } //end NORMALS } else if (nextline.startsWith("COLOR_SCALARS")) { unsigned ptsCount = vertices->size(); if (vertices->size() == 0) { error = CC_FERR_MALFORMED_FILE; break; } else { bool loadRGBColors = vertices->reserveTheRGBTable(); if (!loadRGBColors) ccLog::Warning("[VTK] Not enough memory to load RGB colors!"); for (unsigned i=0; i<ptsCount; ++i) { nextline = inFile.readLine(); if (loadRGBColors) { QStringList parts = nextline.split(" ",QString::SkipEmptyParts); if (parts.size() != 3) { error = CC_FERR_MALFORMED_FILE; break; } colorType rgb[3]; for (unsigned char j=0; j<3; ++j) { bool ok; rgb[j] = (colorType)(parts[j].toDouble(&ok) * (double)MAX_COLOR_COMP); if (!ok) { ccLog::Warning("[VTK] Element #%1 of COLOR_SCALARS data is corrupted!",i); error = CC_FERR_MALFORMED_FILE; break; } } vertices->addRGBColor(rgb); } } } //end COLOR_SCALARS } else if (nextline.startsWith("SCALARS")) { QStringList parts = nextline.split(" ",QString::SkipEmptyParts); lastSfName = "ScalarField"; if (parts.size() > 1) lastSfName = parts[1].replace("_"," "); //SF already exists? if (vertices->getScalarFieldIndexByName(qPrintable(lastSfName)) >= 0) lastSfName += QString(" (%1)").arg(vertices->getNumberOfScalarFields()); //end of SCALARS } else if (nextline.startsWith("LOOKUP_TABLE") || nextline.startsWith("VECTORS")) { unsigned ptsCount = vertices->size(); QStringList parts = nextline.split(" ",QString::SkipEmptyParts); QString itemName = parts[0]; if (parts.size() > 2) { bool ok = false; int valCount = parts[2].toUInt(&ok); if (ok) ptsCount = valCount; } bool createSF = (vertices->size() == ptsCount && vertices->size() != 0); if (acceptLookupTables && !createSF) { ccLog::Warning(QString("[VTK] field %1 has not the right number of points (will be ignored)").arg(itemName)); } createSF &= acceptLookupTables; if (createSF && lastSfName.isNull()) { ccLog::Warning(QString("[VTK] field %1 has no name (will be ignored)").arg(itemName)); createSF = false; } //create scalar field? int newSFIndex = createSF ? vertices->addScalarField(qPrintable(lastSfName)) : -1; CCLib::ScalarField* sf = newSFIndex >= 0 ? vertices->getScalarField(newSFIndex) : 0; lastSfName.clear(); //name is "consumed" for (unsigned i=0; i<ptsCount; ++i) { nextline = inFile.readLine(); if (sf) //otherwise we simply skip the line { QStringList parts = nextline.split(" ",QString::SkipEmptyParts); if (parts.size() != 1) { //get rid of the scalar field :( vertices->deleteScalarField(newSFIndex); sf = 0; if (i == 0) { ccLog::Warning(QString("[VTK] %1 field with more than one element can't be imported as scalar fields!").arg(itemName)); } else { error = CC_FERR_MALFORMED_FILE; break; } } else { bool ok; ScalarType d = static_cast<ScalarType>(nextline.toDouble(&ok)); sf->setValue(i, ok ? d : NAN_VALUE); } } } if (sf) { sf->computeMinAndMax(); vertices->setCurrentDisplayedScalarField(newSFIndex); vertices->showSF(true); } //end of SCALARS } else if (nextline.startsWith("POINT_DATA")) { //check that the number of 'point_data' match the number of points QStringList parts = nextline.split(" ",QString::SkipEmptyParts); acceptLookupTables = false; if (parts.size() > 1) { bool ok; unsigned dataCount = parts[1].toUInt(&ok); if (ok && vertices && dataCount == vertices->size()) { acceptLookupTables = true; } } if (!acceptLookupTables) { ccLog::Warning("[VTK] The number of 'POINT_DATA' doesn't match the number of loaded points... lookup tables will be ignored"); } } else //unhandled property (CELLS, CELL_TYPES, etc.) { QStringList parts = nextline.split(" ",QString::SkipEmptyParts); if (parts.size() < 2) { ccLog::Warning(QString("[VTK] Unhandled element: %1").arg(parts[0])); error = CC_FERR_MALFORMED_FILE; break; } bool ok; unsigned elements = parts[1].toUInt(&ok); if (!ok) { error = CC_FERR_MALFORMED_FILE; break; } for (unsigned i=0; i<elements; ++i) { inFile.readLine(); //ignore } //end unhandled property } if (error != CC_FERR_NO_ERROR) break; } if (error != CC_FERR_NO_ERROR) { if (mesh) delete mesh; if (vertices) delete vertices; return CC_FERR_MALFORMED_FILE; } file.close(); if (mesh && mesh->size() == 0) { delete mesh; mesh = 0; } if (vertices->size() == 0) { delete vertices; return CC_FERR_NO_LOAD; } if (mesh) { container.addChild(mesh); mesh->setVisible(true); mesh->addChild(vertices); vertices->setVisible(false); vertices->setEnabled(false); vertices->setName("Vertices"); vertices->setLocked(true); //DGM: no need to lock it as it is only used by one mesh! //DGM: normals can be per-vertex or per-triangle so it's better to let the user do it himself later //Moreover it's not always good idea if the user doesn't want normals (especially in ccViewer!) //if (!mesh->hasNormals()) // mesh->computeNormals(); ccLog::Warning("[VTK] Mesh has no normal! You can manually compute them (select it then call \"Edit > Normals > Compute\")"); mesh->showNormals(mesh->hasNormals()); if (vertices->hasScalarFields()) { vertices->setCurrentDisplayedScalarField(0); mesh->showSF(true); } if (vertices->hasColors()) mesh->showColors(true); } else { container.addChild(vertices); vertices->setVisible(true); if (vertices->hasNormals()) vertices->showNormals(true); if (vertices->hasScalarFields()) { vertices->setCurrentDisplayedScalarField(0); vertices->showSF(true); } if (vertices->hasColors()) vertices->showColors(true); } return CC_FERR_NO_ERROR; }