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 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; }
CC_FILE_ERROR PlyFilter::loadFile(const char* filename, ccHObject& container, bool alwaysDisplayLoadDialog/*=true*/, bool* coordinatesShiftEnabled/*=0*/, double* coordinatesShift/*=0*/) { //reset statics! s_triCount = 0; s_unsupportedPolygonType = false; s_scalarCount=0; s_IntensityCount=0; s_ColorCount=0; s_NormalCount=0; s_PointCount=0; s_PointDataCorrupted=false; s_AlwaysDisplayLoadDialog=alwaysDisplayLoadDialog; s_ShiftApplyAll=false; s_ShiftAlreadyEnabled = (coordinatesShiftEnabled && *coordinatesShiftEnabled && coordinatesShift); if (s_ShiftAlreadyEnabled) memcpy(s_Pshift,coordinatesShift,sizeof(double)*3); else memset(s_Pshift,0,sizeof(double)*3); /****************/ /*** Header ***/ /****************/ //open a PLY file for reading p_ply ply = ply_open(filename,NULL, 0, NULL); if (!ply) return CC_FERR_READING; ccConsole::PrintDebug("[PLY] Opening file '%s' ...",filename); if (!ply_read_header(ply)) { ply_close(ply); return CC_FERR_WRONG_FILE_TYPE; } //storage mode: little/big endian e_ply_storage_mode storage_mode; get_plystorage_mode(ply,&storage_mode); /******************/ /*** Comments ***/ /******************/ //display comments const char* lastComment = NULL; while ((lastComment = ply_get_next_comment(ply, lastComment))) ccConsole::Print("[PLY][Comment] %s",lastComment); /*******************************/ /*** Elements & properties ***/ /*******************************/ //Point-based elements (points, colors, normals, etc.) std::vector<plyElement> pointElements; //Mesh-based elements (vertices, etc.) std::vector<plyElement> meshElements; //Point-based element properties (coordinates, color components, etc.) std::vector<plyProperty> stdProperties; //Mesh-based element properties (vertex indexes, etc.) std::vector<plyProperty> listProperties; unsigned i=0; //last read element plyElement lastElement; lastElement.elem = 0; while ((lastElement.elem = ply_get_next_element(ply, lastElement.elem))) { //we get next element info ply_get_element_info(lastElement.elem, &lastElement.elementName, &lastElement.elementInstances); if (lastElement.elementInstances == 0) { ccConsole::Warning("[PLY] Element '%s' was ignored as it has 0 instance!",lastElement.elementName); continue; } lastElement.properties.clear(); lastElement.propertiesCount=0; lastElement.isList=false; //printf("Element: %s\n",lastElement.elementName); //last read property plyProperty lastProperty; lastProperty.prop = 0; lastProperty.elemIndex = 0; while ((lastProperty.prop = ply_get_next_property(lastElement.elem,lastProperty.prop))) { //we get next property info ply_get_property_info(lastProperty.prop, &lastProperty.propName, &lastProperty.type, &lastProperty.length_type, &lastProperty.value_type); //printf("\tProperty: %s (%s)\n",lastProperty.propName,e_ply_type_names[lastProperty.type]); if (lastProperty.type == 16) //PLY_LIST lastElement.isList = true; lastElement.properties.push_back(lastProperty); ++lastElement.propertiesCount; } //if we have a "mesh-like" element if (lastElement.isList) { //we store its properties in 'listProperties' for (i=0;i<lastElement.properties.size();++i) { plyProperty& prop = lastElement.properties[i]; prop.elemIndex = meshElements.size(); //we only keep track of lists (we can't handle per triangle scalars) if (prop.type == 16) listProperties.push_back(prop); else { ccConsole::Warning("[PLY] Unhandled property: [%s:%s] (%s)", lastElement.elementName, prop.propName, e_ply_type_names[prop.type]); } } meshElements.push_back(lastElement); } else //else if we have a "point-like" element { //we store its properties in 'stdProperties' for (i=0;i<lastElement.properties.size();++i) { plyProperty& prop = lastElement.properties[i]; prop.elemIndex = pointElements.size(); stdProperties.push_back(prop); } pointElements.push_back(lastElement); } } //We need some points at least! if (pointElements.empty()) { ply_close(ply); return CC_FERR_NO_LOAD; } /**********************/ /*** Objects info ***/ /**********************/ const char* lastObjInfo = NULL; while ((lastObjInfo = ply_get_next_obj_info(ply, lastObjInfo))) ccConsole::Print("[PLY][Info] %s",lastObjInfo); /****************/ /*** Dialog ***/ /****************/ //properties indexes (0=unassigned) static const unsigned nStdProp=11; int stdPropIndexes[nStdProp]={0,0,0,0,0,0,0,0,0,0,0}; int& xIndex = stdPropIndexes[0]; int& yIndex = stdPropIndexes[1]; int& zIndex = stdPropIndexes[2]; int& nxIndex = stdPropIndexes[3]; int& nyIndex = stdPropIndexes[4]; int& nzIndex = stdPropIndexes[5]; int& rIndex = stdPropIndexes[6]; int& gIndex = stdPropIndexes[7]; int& bIndex = stdPropIndexes[8]; int& iIndex = stdPropIndexes[9]; int& sfIndex = stdPropIndexes[10]; static const unsigned nListProp=1; int listPropIndexes[nListProp]={0}; int& facesIndex = listPropIndexes[0]; //Combo box items for standard properties (coordinates, color components, etc.) QStringList stdPropsText; stdPropsText << QString("None"); for (i=1; i<=stdProperties.size(); ++i) { plyProperty& pp = stdProperties[i-1]; QString itemText = QString("%1 - %2 [%3]").arg(pointElements[pp.elemIndex].elementName).arg(pp.propName).arg(e_ply_type_names[pp.type]); assert(pp.type!=16); //we don't want any PLY_LIST here stdPropsText << itemText; QString elementName = QString(pointElements[pp.elemIndex].elementName).toUpper(); QString propName = QString(pp.propName).toUpper(); if (nxIndex == 0 && (propName.contains("NX") || (elementName.contains("NORM") && propName.endsWith("X")))) nxIndex = i; else if (nyIndex == 0 && (propName.contains("NY") || (elementName.contains("NORM") && propName.endsWith("Y")))) nyIndex = i; else if (nzIndex == 0 && (propName.contains("NZ") || (elementName.contains("NORM") && propName.endsWith("Z")))) nzIndex = i; else if (rIndex == 0 && (propName.contains("RED") || (elementName.contains("COL") && propName.endsWith("R")))) rIndex = i; else if (gIndex == 0 && (propName.contains("GREEN") || (elementName.contains("COL") && propName.endsWith("G")))) gIndex = i; else if (bIndex == 0 && (propName.contains("BLUE") || (elementName.contains("COL") && propName.endsWith("B")))) bIndex = i; else if (iIndex == 0 && (propName.contains("INTENSITY") || propName.contains("GRAY") || propName.contains("GREY") || (elementName.contains("COL") && propName.endsWith("I")))) iIndex = i; else if (elementName.contains("VERT") || elementName.contains("POINT")) { if (sfIndex == 0 && propName.contains("SCAL")) sfIndex = i; else if (xIndex == 0 && propName.endsWith("X")) xIndex = i; else if (yIndex == 0 && propName.endsWith("Y")) yIndex = i; else if (zIndex == 0 && propName.endsWith("Z")) zIndex = i; } else if (sfIndex == 0 && (propName.contains("SCAL") || propName.contains("VAL"))) sfIndex = i; } //Combo box items for list properties (vertex indexes, etc.) QStringList listPropsText; listPropsText << QString("None"); for (i=0; i<listProperties.size(); ++i) { plyProperty& pp = listProperties[i]; QString itemText = QString("%0 - %1 [%2]").arg(meshElements[pp.elemIndex].elementName).arg(pp.propName).arg(e_ply_type_names[pp.type]); assert(pp.type==16); //we only want PLY_LIST here listPropsText << itemText; QString elementName = QString(meshElements[pp.elemIndex].elementName).toUpper(); QString propName = QString(pp.propName).toUpper(); if (facesIndex == 0 && (elementName.contains("FACE") || elementName.contains("TRI")) && propName.contains("IND")) facesIndex = i+1; } //combo-box max visible items int stdPropsCount = stdPropsText.count(); int listPropsCount = listPropsText.count(); //we need at least 2 coordinates! if (stdPropsCount<2) { return CC_FERR_BAD_ENTITY_TYPE; } else if (stdPropsCount<4 && !alwaysDisplayLoadDialog) { //brute force heuristic xIndex = 1; yIndex = 2; zIndex = (stdPropsCount>3 ? 3 : 0); facesIndex = (listPropsCount>1 ? 1 : 0); } else { //we count all assigned properties int assignedStdProperties = 0; for (i=0;i<nStdProp;++i) if (stdPropIndexes[i]>0) ++assignedStdProperties; int assignedListProperties = 0; for (i=0;i<nListProp;++i) if (listPropIndexes[i]>0) ++assignedListProperties; if (alwaysDisplayLoadDialog || stdPropsCount > assignedStdProperties+1 || //+1 because of the first item in the combo box ('none') listPropsCount > assignedListProperties+1) //+1 because of the first item in the combo box ('none') { PlyOpenDlg pod/*(MainWindow::TheInstance())*/; pod.plyTypeEdit->setText(e_ply_storage_mode_names[storage_mode]); pod.elementsEdit->setText(QString::number(pointElements.size())); pod.propertiesEdit->setText(QString::number(listProperties.size()+stdProperties.size())); //we fill every combo box pod.xComboBox->addItems(stdPropsText); pod.xComboBox->setCurrentIndex(xIndex); pod.xComboBox->setMaxVisibleItems(stdPropsCount); pod.yComboBox->addItems(stdPropsText); pod.yComboBox->setCurrentIndex(yIndex); pod.yComboBox->setMaxVisibleItems(stdPropsCount); pod.zComboBox->addItems(stdPropsText); pod.zComboBox->setCurrentIndex(zIndex); pod.zComboBox->setMaxVisibleItems(stdPropsCount); pod.rComboBox->addItems(stdPropsText); pod.rComboBox->setCurrentIndex(rIndex); pod.rComboBox->setMaxVisibleItems(stdPropsCount); pod.gComboBox->addItems(stdPropsText); pod.gComboBox->setCurrentIndex(gIndex); pod.gComboBox->setMaxVisibleItems(stdPropsCount); pod.bComboBox->addItems(stdPropsText); pod.bComboBox->setCurrentIndex(bIndex); pod.bComboBox->setMaxVisibleItems(stdPropsCount); pod.iComboBox->addItems(stdPropsText); pod.iComboBox->setCurrentIndex(iIndex); pod.iComboBox->setMaxVisibleItems(stdPropsCount); pod.sfComboBox->addItems(stdPropsText); pod.sfComboBox->setCurrentIndex(sfIndex); pod.sfComboBox->setMaxVisibleItems(stdPropsCount); pod.nxComboBox->addItems(stdPropsText); pod.nxComboBox->setCurrentIndex(nxIndex); pod.nxComboBox->setMaxVisibleItems(stdPropsCount); pod.nyComboBox->addItems(stdPropsText); pod.nyComboBox->setCurrentIndex(nyIndex); pod.nyComboBox->setMaxVisibleItems(stdPropsCount); pod.nzComboBox->addItems(stdPropsText); pod.nzComboBox->setCurrentIndex(nzIndex); pod.nzComboBox->setMaxVisibleItems(stdPropsCount); pod.facesComboBox->addItems(listPropsText); pod.facesComboBox->setCurrentIndex(facesIndex); pod.facesComboBox->setMaxVisibleItems(listPropsCount); //We execute dialog if (!pod.exec()) { ply_close(ply); return CC_FERR_CANCELED_BY_USER; } //Force events processing (to hide dialog) QCoreApplication::processEvents(); xIndex = pod.xComboBox->currentIndex(); yIndex = pod.yComboBox->currentIndex(); zIndex = pod.zComboBox->currentIndex(); nxIndex = pod.nxComboBox->currentIndex(); nyIndex = pod.nyComboBox->currentIndex(); nzIndex = pod.nzComboBox->currentIndex(); rIndex = pod.rComboBox->currentIndex(); gIndex = pod.gComboBox->currentIndex(); bIndex = pod.bComboBox->currentIndex(); iIndex = pod.iComboBox->currentIndex(); facesIndex = pod.facesComboBox->currentIndex(); sfIndex = pod.sfComboBox->currentIndex(); } } /*************************/ /*** Callbacks setup ***/ /*************************/ //Main point cloud ccPointCloud* cloud = new ccPointCloud("unnamed - Cloud"); /* POINTS (X,Y,Z) */ unsigned numberOfPoints=0; assert(xIndex != yIndex && xIndex != zIndex && yIndex != zIndex); //POINTS (X) if (xIndex>0) { long flags = ELEM_POS_0; //X coordinate if (xIndex > yIndex && xIndex > zIndex) flags |= ELEM_EOL; plyProperty& pp = stdProperties[xIndex-1]; ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, vertex_cb, cloud, flags); numberOfPoints = pointElements[pp.elemIndex].elementInstances; } //POINTS (Y) if (yIndex>0) { long flags = ELEM_POS_1; //Y coordinate if (yIndex > xIndex && yIndex > zIndex) flags |= ELEM_EOL; plyProperty& pp = stdProperties[yIndex-1]; ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, vertex_cb, cloud, flags); if (numberOfPoints > 0) { if ((long)numberOfPoints != pointElements[pp.elemIndex].elementInstances) { ccConsole::Warning("[PLY] Bad/uncompatible assignation of point properties!"); delete cloud; ply_close(ply); return CC_FERR_BAD_ENTITY_TYPE; } } else numberOfPoints = pointElements[pp.elemIndex].elementInstances; } //POINTS (Z) if (zIndex>0) { long flags = ELEM_POS_2; //Z coordinate if (zIndex > xIndex && zIndex > yIndex) flags |= ELEM_EOL; plyProperty& pp = stdProperties[zIndex-1]; ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, vertex_cb, cloud, flags); if (numberOfPoints > 0) { if ((long)numberOfPoints != pointElements[pp.elemIndex].elementInstances) { ccConsole::Warning("[PLY] Bad/uncompatible assignation of point properties!"); delete cloud; ply_close(ply); return CC_FERR_BAD_ENTITY_TYPE; } } else numberOfPoints = pointElements[pp.elemIndex].elementInstances; } if (numberOfPoints == 0 || !cloud->reserveThePointsTable(numberOfPoints)) { delete cloud; ply_close(ply); return CC_FERR_NOT_ENOUGH_MEMORY; } /* NORMALS (X,Y,Z) */ unsigned numberOfNormals=0; assert(nxIndex == 0 || (nxIndex != nyIndex && nxIndex != nzIndex)); assert(nyIndex == 0 || (nyIndex != nxIndex && nyIndex != nzIndex)); assert(nzIndex == 0 || (nzIndex != nxIndex && nzIndex != nyIndex)); //NORMALS (X) if (nxIndex>0) { long flags = ELEM_POS_0; //Nx if (nxIndex > nyIndex && nxIndex > nzIndex) flags |= ELEM_EOL; plyProperty& pp = stdProperties[nxIndex-1]; ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, normal_cb, cloud, flags); numberOfNormals = pointElements[pp.elemIndex].elementInstances; } //NORMALS (Y) if (nyIndex>0) { long flags = ELEM_POS_1; //Ny if (nyIndex > nxIndex && nyIndex > nzIndex) flags |= ELEM_EOL; plyProperty& pp = stdProperties[nyIndex-1]; ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, normal_cb, cloud, flags); numberOfNormals = ccMax(numberOfNormals, (unsigned)pointElements[pp.elemIndex].elementInstances); } //NORMALS (Z) if (nzIndex>0) { long flags = ELEM_POS_2; //Nz if (nzIndex > nxIndex && nzIndex > nyIndex) flags |= ELEM_EOL; plyProperty& pp = stdProperties[nzIndex-1]; ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, normal_cb, cloud, flags); numberOfNormals = ccMax(numberOfNormals, (unsigned)pointElements[pp.elemIndex].elementInstances); } //We check that the number of normals corresponds to the number of points if (numberOfNormals > 0) { if (numberOfPoints != numberOfNormals) { ccConsole::Warning("[PLY] The number of normals doesn't match the number of points!"); delete cloud; ply_close(ply); return CC_FERR_BAD_ENTITY_TYPE; } if (!cloud->reserveTheNormsTable()) { delete cloud; ply_close(ply); return CC_FERR_NOT_ENOUGH_MEMORY; } cloud->showNormals(true); } /* COLORS (R,G,B) */ unsigned numberOfColors=0; assert(rIndex == 0 || (rIndex != gIndex && rIndex != bIndex)); assert(gIndex == 0 || (gIndex != rIndex && gIndex != bIndex)); assert(bIndex == 0 || (bIndex != rIndex && bIndex != gIndex)); if (rIndex>0) { long flags = ELEM_POS_0; //R if (rIndex > gIndex && rIndex > bIndex) flags |= ELEM_EOL; plyProperty& pp = stdProperties[rIndex-1]; ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, rgb_cb, cloud, flags); numberOfColors = pointElements[pp.elemIndex].elementInstances; } if (gIndex>0) { long flags = ELEM_POS_1; //G if (gIndex > rIndex && gIndex > bIndex) flags |= ELEM_EOL; plyProperty& pp = stdProperties[gIndex-1]; ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, rgb_cb, cloud, flags); numberOfColors = ccMax(numberOfColors, (unsigned)pointElements[pp.elemIndex].elementInstances); } if (bIndex>0) { long flags = ELEM_POS_2; //B if (bIndex > rIndex && bIndex > gIndex) flags |= ELEM_EOL; plyProperty& pp = stdProperties[bIndex-1]; ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, rgb_cb, cloud, flags); numberOfColors = ccMax(numberOfColors, (unsigned)pointElements[pp.elemIndex].elementInstances); } /* Intensity (I) */ //INTENSITE (G) if (iIndex>0) { if (numberOfColors>0) { ccConsole::Error("Can't import colors AND intensity (intensities will be ignored)!"); ccConsole::Warning("[PLY] intensities will be ignored"); } else { plyProperty pp = stdProperties[iIndex-1]; ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, grey_cb, cloud, 0); numberOfColors = pointElements[pp.elemIndex].elementInstances; } } //We check that the number of colors corresponds to the number of points if (numberOfColors > 0) { if (numberOfPoints != numberOfColors) { ccConsole::Warning("The number of colors doesn't match the number of points!"); delete cloud; ply_close(ply); return CC_FERR_BAD_ENTITY_TYPE; } if (!cloud->reserveTheRGBTable()) { delete cloud; ply_close(ply); return CC_FERR_NOT_ENOUGH_MEMORY; } cloud->showColors(true); } /* SCALAR FIELD (SF) */ unsigned numberOfScalars=0; if (sfIndex>0) { plyProperty& pp = stdProperties[sfIndex-1]; numberOfScalars = pointElements[pp.elemIndex].elementInstances; //does the number of scalars matches the number of points? if (numberOfPoints != numberOfScalars) { ccConsole::Error("The number of scalars doesn't match the number of points (they will be ignored)!"); ccConsole::Warning("[PLY] Scalar field ignored!"); numberOfScalars = 0; } else if (!cloud->enableScalarField()) { ccConsole::Error("Not enough memory to load scalar field (they will be ignored)!"); ccConsole::Warning("[PLY] Scalar field ignored!"); numberOfScalars = 0; } else { CCLib::ScalarField* sf = cloud->getCurrentInScalarField(); if (sf) { QString qPropName(pp.propName); if (qPropName.startsWith("scalar_") && qPropName.length()>7) { //remove the 'scalar_' prefix added when saving SF with CC! qPropName = qPropName.mid(7).replace('_',' '); sf->setName(qPrintable(qPropName)); } else { sf->setName(pp.propName); } } ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, scalar_cb, cloud, 1); } cloud->showSF(true); } /* MESH FACETS (TRI) */ ccMesh* mesh = 0; unsigned numberOfFacets=0; if (facesIndex>0) { plyProperty& pp = listProperties[facesIndex-1]; assert(pp.type==16); //we only accept PLY_LIST here! mesh = new ccMesh(cloud); numberOfFacets = meshElements[pp.elemIndex].elementInstances; if (!mesh->reserve(numberOfFacets)) { ccConsole::Error("Not enough memory to load facets (they will be ignored)!"); ccConsole::Warning("[PLY] Mesh ignored!"); delete mesh; mesh = 0; numberOfFacets = 0; } else { ply_set_read_cb(ply, meshElements[pp.elemIndex].elementName, pp.propName, face_cb, mesh, 0); } } QProgressDialog progressDlg(QString("Loading in progress..."),0,0,0,0,Qt::Popup); progressDlg.setMinimumDuration(0); progressDlg.setModal(true); progressDlg.show(); QApplication::processEvents(); int success = ply_read(ply); progressDlg.close(); ply_close(ply); if (success<1) { if (mesh) delete mesh; delete cloud; return CC_FERR_READING; } //we check mesh if (mesh && mesh->size()==0) { if (s_unsupportedPolygonType) ccConsole::Error("Mesh is not triangular! (unsupported)"); else ccConsole::Error("Mesh is empty!"); delete mesh; mesh=0; } //we save coordinates shift information if (s_ShiftApplyAll && coordinatesShiftEnabled && coordinatesShift) { *coordinatesShiftEnabled = true; coordinatesShift[0] = s_Pshift[0]; coordinatesShift[1] = s_Pshift[1]; coordinatesShift[2] = s_Pshift[2]; } //we update scalar field CCLib::ScalarField* sf = cloud->getCurrentInScalarField(); if (sf) { sf->setPositive(!s_negSF); sf->computeMinAndMax(); int sfIdx = cloud->getCurrentInScalarFieldIndex(); cloud->setCurrentDisplayedScalarField(sfIdx); cloud->showSF(sfIdx>=0); } if (mesh) { assert(s_triCount > 0); //check number of loaded facets against 'theoretical' number if (s_triCount<numberOfFacets) { mesh->resize(s_triCount); ccConsole::Warning("[PLY] Missing vertex indexes!"); } //check that vertex indices start at 0 unsigned minVertIndex=numberOfPoints,maxVertIndex=0; for (unsigned i=0;i<s_triCount;++i) { const CCLib::TriangleSummitsIndexes* tri = mesh->getTriangleIndexes(i); if (tri->i1 < minVertIndex) minVertIndex = tri->i1; else if (tri->i1 > maxVertIndex) maxVertIndex = tri->i1; if (tri->i2 < minVertIndex) minVertIndex = tri->i2; else if (tri->i2 > maxVertIndex) maxVertIndex = tri->i2; if (tri->i3 < minVertIndex) minVertIndex = tri->i3; else if (tri->i3 > maxVertIndex) maxVertIndex = tri->i3; } if (maxVertIndex>=numberOfPoints) { if (maxVertIndex == numberOfPoints && minVertIndex > 0) { ccLog::Warning("[PLY] Vertex indices seem to be shifted (+1)! We will try to 'unshift' indices (otherwise file is corrupted...)"); for (unsigned i=0;i<s_triCount;++i) { CCLib::TriangleSummitsIndexes* tri = mesh->getTriangleIndexes(i); --tri->i1; --tri->i2; --tri->i3; } } else //file is definitely corrupted! { ccLog::Warning("[PLY] Invalid vertex indices!"); delete mesh; delete cloud; return CC_FERR_MALFORMED_FILE; } } mesh->addChild(cloud); cloud->setEnabled(false); cloud->setName("Vertices"); //cloud->setLocked(true); //DGM: no need to lock it as it is only used by one mesh! if (cloud->hasColors()) mesh->showColors(true); if (cloud->hasDisplayedScalarField()) mesh->showSF(true); if (cloud->hasNormals()) mesh->showNormals(true); else mesh->computeNormals(); container.addChild(mesh); } else { container.addChild(cloud); } return CC_FERR_NO_ERROR; }
CC_FILE_ERROR PVFilter::loadFile(QString filename, ccHObject& container, LoadParameters& parameters) { //opening file QFile in(filename); if (!in.open(QIODevice::ReadOnly)) return CC_FERR_READING; //we deduce the points number from the file size qint64 fileSize = in.size(); qint64 singlePointSize = 4*sizeof(float); //check that size is ok if (fileSize == 0) return CC_FERR_NO_LOAD; if ((fileSize % singlePointSize) != 0) return CC_FERR_MALFORMED_FILE; unsigned numberOfPoints = static_cast<unsigned>(fileSize / singlePointSize); //progress dialog ccProgressDialog pdlg(true); //cancel available CCLib::NormalizedProgress nprogress(&pdlg,numberOfPoints); pdlg.setMethodTitle("Open PV file"); pdlg.setInfo(qPrintable(QString("Points: %1").arg(numberOfPoints))); pdlg.start(); ccPointCloud* loadedCloud = 0; //if the file is too big, it will be chuncked in multiple parts unsigned chunkIndex = 0; unsigned fileChunkPos = 0; unsigned fileChunkSize = 0; //number of points read for the current cloud part unsigned pointsRead = 0; CC_FILE_ERROR result = CC_FERR_NO_ERROR; for (unsigned i=0;i<numberOfPoints;i++) { //if we reach the max. cloud size limit, we cerate a new chunk if (pointsRead == fileChunkPos+fileChunkSize) { if (loadedCloud) { int sfIdx = loadedCloud->getCurrentInScalarFieldIndex(); if (sfIdx>=0) { CCLib::ScalarField* sf = loadedCloud->getScalarField(sfIdx); sf->computeMinAndMax(); loadedCloud->setCurrentDisplayedScalarField(sfIdx); loadedCloud->showSF(true); } container.addChild(loadedCloud); } fileChunkPos = pointsRead; fileChunkSize = std::min<unsigned>(numberOfPoints-pointsRead,CC_MAX_NUMBER_OF_POINTS_PER_CLOUD); loadedCloud = new ccPointCloud(QString("unnamed - Cloud #%1").arg(++chunkIndex)); if (!loadedCloud || !loadedCloud->reserveThePointsTable(fileChunkSize) || !loadedCloud->enableScalarField()) { result = CC_FERR_NOT_ENOUGH_MEMORY; if (loadedCloud) delete loadedCloud; loadedCloud=0; break; } } //we read the 3 coordinates of the point float rBuff[3]; if (in.read((char*)rBuff,3*sizeof(float))>=0) { //conversion to CCVector3 CCVector3 P((PointCoordinateType)rBuff[0], (PointCoordinateType)rBuff[1], (PointCoordinateType)rBuff[2]); loadedCloud->addPoint(P); } else { result = CC_FERR_READING; break; } //then the scalar value if (in.read((char*)rBuff,sizeof(float))>=0) { loadedCloud->setPointScalarValue(pointsRead,(ScalarType)rBuff[0]); } else { //add fake scalar value for consistency then break loadedCloud->setPointScalarValue(pointsRead,0); result = CC_FERR_READING; break; } ++pointsRead; if (!nprogress.oneStep()) { result = CC_FERR_CANCELED_BY_USER; break; } } in.close(); if (loadedCloud) { if (loadedCloud->size() < loadedCloud->capacity()) loadedCloud->resize(loadedCloud->size()); int sfIdx = loadedCloud->getCurrentInScalarFieldIndex(); if (sfIdx>=0) { CCLib::ScalarField* sf = loadedCloud->getScalarField(sfIdx); sf->computeMinAndMax(); loadedCloud->setCurrentDisplayedScalarField(sfIdx); loadedCloud->showSF(true); } container.addChild(loadedCloud); } return result; }
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; }
CC_FILE_ERROR ShpFilter::loadFile(QString filename, ccHObject& container, LoadParameters& parameters) { QFile file(filename); if (!file.open(QIODevice::ReadOnly)) return CC_FERR_READING; //global shift CCVector3d Pshift(0,0,0); //read header (refer to ESRI Shapefile Technical Description) if (file.size() < 100) return CC_FERR_MALFORMED_FILE; char header[100]; file.read(header,100); int32_t fileLength = 0; { /*** WARNING: the beginning of the header is written with big endianness! ***/ const char* _header = header; //Byte 0: SHP code const int32_t code = qFromBigEndian<int32_t>(*reinterpret_cast<const int32_t*>(_header)); if (code != 9994) { return CC_FERR_MALFORMED_FILE; } _header += 4; //Byte 4: unused (20 bytes) _header += 20; //Byte 24: file length (will be written... later ;) fileLength = qFromBigEndian<int32_t>(*reinterpret_cast<const int32_t*>(_header)); fileLength *= 2; //fileLength is measured in 16-bit words _header += 4; /*** WARNING: from now on, we only read data with little endianness! ***/ //Byte 28: file verion const int32_t version = qFromLittleEndian<int32_t>(*reinterpret_cast<const int32_t*>(_header)); _header += 4; //Byte 32: shape type int32_t shapeTypeInt = qFromLittleEndian<int32_t>(*reinterpret_cast<const int32_t*>(_header)); _header += 4; ccLog::Print(QString("[SHP] Version: %1 - type: %2").arg(version).arg(ToString(static_cast<ESRI_SHAPE_TYPE>(shapeTypeInt)))); //X and Y bounaries //Byte 36: box X min double xMin = qFromLittleEndian<double>(*reinterpret_cast<const double*>(_header)); _header += 8; //Byte 44: box Y min double xMax = qFromLittleEndian<double>(*reinterpret_cast<const double*>(_header)); _header += 8; //Byte 52: box X max double yMin = qFromLittleEndian<double>(*reinterpret_cast<const double*>(_header)); _header += 8; //Byte 60: box Y max double yMax = qFromLittleEndian<double>(*reinterpret_cast<const double*>(_header)); _header += 8; //Z bounaries //Unused, with value 0.0, if not Measured or Z type //Byte 68: box Z min double zMin = qFromLittleEndian<double>(*reinterpret_cast<const double*>(_header)); _header += 8; //Byte 76: box Z max double zMax = qFromLittleEndian<double>(*reinterpret_cast<const double*>(_header)); _header += 8; CCVector3d Pmin(xMin,yMin,zMin); if (HandleGlobalShift(Pmin,Pshift,parameters)) { ccLog::Warning("[SHP] Entities will be recentered! Translation: (%.2f,%.2f,%.2f)",Pshift.x,Pshift.y,Pshift.z); } //M bounaries (M = measures) //Byte 84: M min double mMin = qFromLittleEndian<double>(*reinterpret_cast<const double*>(_header)); _header += 8; //Byte 92: M max double mMax = qFromLittleEndian<double>(*reinterpret_cast<const double*>(_header)); _header += 8; } assert(fileLength >= 100); if (fileLength < 100) { assert(false); return CC_FERR_MALFORMED_FILE; } fileLength -= 100; if (fileLength == 0) { return CC_FERR_NO_LOAD; } //load shapes CC_FILE_ERROR error = CC_FERR_NO_ERROR; ccPointCloud* singlePoints = 0; qint64 pos = file.pos(); while (fileLength >= 12) { file.seek(pos); assert(pos + fileLength == file.size()); //load shape record in main SHP file { file.read(header,8); //Byte 0: Record Number int32_t recordNumber = qFromBigEndian<int32_t>(*reinterpret_cast<const int32_t*>(header)); //Record numbers begin at 1 //Byte 4: Content Length int32_t recordSize = qFromBigEndian<int32_t>(*reinterpret_cast<const int32_t*>(header+4)); //Record numbers begin at 1 recordSize *= 2; //recordSize is measured in 16-bit words fileLength -= 8; pos += 8; if (fileLength < recordSize) { assert(false); error = CC_FERR_MALFORMED_FILE; break; } fileLength -= recordSize; pos += recordSize; //Record start (byte 0): Shape Type if (recordSize < 4) { assert(false); error = CC_FERR_MALFORMED_FILE; break; } file.read(header,4); recordSize -= 4; int32_t shapeTypeInt = qToLittleEndian<int32_t>(*reinterpret_cast<const int32_t*>(header)); ccLog::Print(QString("[SHP] Record #%1 - type: %2 (%3 bytes)").arg(recordNumber).arg(ToString(static_cast<ESRI_SHAPE_TYPE>(shapeTypeInt))).arg(recordSize)); switch (shapeTypeInt) { case SHP_POLYLINE: case SHP_POLYLINE_Z: case SHP_POLYGON: case SHP_POLYGON_Z: error = LoadPolyline(file,container,recordNumber,static_cast<ESRI_SHAPE_TYPE>(shapeTypeInt),Pshift); break; case SHP_MULTI_POINT: case SHP_MULTI_POINT_Z: case SHP_MULTI_POINT_M: error = LoadCloud(file,container,recordNumber,static_cast<ESRI_SHAPE_TYPE>(shapeTypeInt),Pshift); break; case SHP_POINT: case SHP_POINT_Z: case SHP_POINT_M: error = LoadSinglePoint(file,singlePoints,static_cast<ESRI_SHAPE_TYPE>(shapeTypeInt),Pshift); break; //case SHP_MULTI_PATCH: // error = LoadMesh(file,recordSize); // break; case SHP_NULL_SHAPE: //ignored break; default: //unhandled entity ccLog::Warning("[SHP] Unhandled type!"); break; } } if (error != CC_FERR_NO_ERROR) break; } if (singlePoints) { if (singlePoints->size() == 0) { delete singlePoints; singlePoints = 0; } else { CCLib::ScalarField* sf = singlePoints->getScalarField(0); if (sf) { sf->computeMinAndMax(); singlePoints->showSF(true); } container.addChild(singlePoints); } } return error; }
CC_FILE_ERROR UltFilter::loadFile(const char* filename, ccHObject& container, bool alwaysDisplayLoadDialog/*=true*/, bool* coordinatesShiftEnabled/*=0*/, double* coordinatesShift/*=0*/) { //ccConsole::Print("[BinFilter::loadFile] Opening binary file '%s'...\n",filename); assert(filename); //file size long size = QFileInfo(filename).size(); if ( size == 0 || ((size % sizeof(MarkersFrame)) != 0)) return CC_FERR_MALFORMED_FILE; //number of transformations in file long count = size / sizeof(MarkersFrame); ccConsole::Print("[TransBuffer] Found %i trans. in file '%s'",count,filename); if (count<1) return CC_FERR_NO_LOAD; ccPointCloud* cloud = new ccPointCloud(); if (!cloud->reserve(count) || !cloud->enableScalarField()) { delete cloud; return CC_FERR_NOT_ENOUGH_MEMORY; } ccProgressDialog pdlg(true); pdlg.setMethodTitle("Open Ult File"); CCLib::NormalizedProgress nprogress(&pdlg,count); pdlg.reset(); pdlg.setInfo(qPrintable(QString("Transformations: %1").arg(count))); pdlg.start(); QApplication::processEvents(); FILE* fp = fopen(filename,"rb"); if (!fp) { delete cloud; return CC_FERR_READING; } //which marker is the reference? QMessageBox::StandardButton tibiaIsRef = QMessageBox::question(0, "Choose reference", "Tibia as reference (yes)? Or femur (no)? Or none (no to all)", QMessageBox::Yes | QMessageBox::No | QMessageBox::NoToAll, QMessageBox::Yes ); MARKER_ROLE referenceRole = MARKER_LOCALIZER; if (tibiaIsRef == QMessageBox::Yes) referenceRole = MARKER_TIBIA; else if (tibiaIsRef == QMessageBox::No) referenceRole = MARKER_FEMUR; //To apply a predefined pointer tip //CCVector3 tip(0,0,0); CCVector3 tip(-90.07f, -17.68f, 18.29f); MarkersFrame currentframe; MarkerState& currentMarker = currentframe.states[MARKER_POINTER]; MarkerState* referenceMarker = 0; if (referenceRole != MARKER_LOCALIZER) referenceMarker = currentframe.states+referenceRole; unsigned MarkersFrameSize = sizeof(MarkersFrame); unsigned realCount=0; for (long i=0;i<count;++i) { if (fread(¤tframe,MarkersFrameSize,1,fp)==0) { fclose(fp); delete cloud; return CC_FERR_READING; } if (currentMarker.visible && (!referenceMarker || referenceMarker->visible)) { CCVector3 P(tip); ccGLMatrix trans = currentMarker.pos; if (referenceMarker) trans = referenceMarker->pos.inverse() * trans; trans.apply(P); cloud->addPoint(P); cloud->setPointScalarValue(realCount,currentMarker.pos.timestamp); ++realCount; } if (!nprogress.oneStep()) break; } fclose(fp); if (realCount==0) { delete cloud; return CC_FERR_NO_LOAD; } cloud->resize(realCount); //we update scalar field CCLib::ScalarField* sf = cloud->getCurrentInScalarField(); if (sf) { sf->setPositive(true); sf->computeMinAndMax(); cloud->setCurrentDisplayedScalarField(cloud->getCurrentInScalarFieldIndex()); } container.addChild(cloud); return CC_FERR_NO_ERROR; }
//==================================================loadFile=================================================// CC_FILE_ERROR PlyFilter::loadFile(QString filename, ccHObject& container, LoadParameters& parameters) { //reset statics! s_triCount = 0;//三角面片的个数 s_unsupportedPolygonType = false;//支持多边形类型 s_texCoordCount = 0;//纹理坐标个数 s_invalidTexCoordinates = false;//纹理坐标无效 s_totalScalarCount = 0;// s_IntensityCount = 0;// s_ColorCount = 0;//颜色个数 s_NormalCount = 0;//法向量个数 s_PointCount = 0;//点的个数 s_PointDataCorrupted = false; s_loadParameters = parameters; s_Pshift = CCVector3d(0,0,0); /****************/ /*** Header ***/ /****************/ //open a PLY file for reading p_ply ply = ply_open(qPrintable(filename), NULL, 0, NULL); if (!ply) return CC_FERR_READING; //ccLog::PrintDebug(QString("[PLY] Opening file '%1' ...").arg(filename)); ccLog::PrintDebug(QString("[PLY] 打开文件 '%1' ...").arg(filename)); if (!ply_read_header(ply)) { ply_close(ply); return CC_FERR_WRONG_FILE_TYPE; } //storage mode: little/big endian e_ply_storage_mode storage_mode; get_plystorage_mode(ply,&storage_mode); /*****************/ /*** Texture ***/ /*****************/ //eventual texture file declared in the comments (keyword: TEXTUREFILE) QString textureFileName; //texture coordinates TextureCoordsContainer* texCoords = 0; /******************/ /*** Comments ***/ /******************/ { const char* lastComment = NULL; //display comments while ((lastComment = ply_get_next_comment(ply, lastComment))) { ccLog::Print("[PLY][Comment] %s",lastComment); //specific case: TextureFile 'filename.ext' if (QString(lastComment).toUpper().startsWith("TEXTUREFILE ")) textureFileName = QString(lastComment).mid(12).trimmed(); } } /*******************************/ /*** Elements & properties ***/ /*******************************/ //Point-based elements (points, colors, normals, etc.) std::vector<plyElement> pointElements; //Mesh-based elements (vertices, etc.) std::vector<plyElement> meshElements; //Point-based element properties (coordinates, color components, etc.) std::vector<plyProperty> stdProperties; //Mesh-based element properties (vertex indexes, etc.) std::vector<plyProperty> listProperties; //last read element plyElement lastElement; lastElement.elem = 0; while ((lastElement.elem = ply_get_next_element(ply, lastElement.elem))) { //we get next element info ply_get_element_info(lastElement.elem, &lastElement.elementName, &lastElement.elementInstances); if (lastElement.elementInstances == 0) { ccLog::Warning("[PLY] Element '%s' was ignored as it has 0 instance!",lastElement.elementName); continue; } lastElement.properties.clear(); lastElement.propertiesCount=0; lastElement.isList=false; //printf("Element: %s\n",lastElement.elementName); //last read property plyProperty lastProperty; lastProperty.prop = 0; lastProperty.elemIndex = 0; while ((lastProperty.prop = ply_get_next_property(lastElement.elem,lastProperty.prop))) { //we get next property info ply_get_property_info(lastProperty.prop, &lastProperty.propName, &lastProperty.type, &lastProperty.length_type, &lastProperty.value_type); //printf("\tProperty: %s (%s)\n",lastProperty.propName,e_ply_type_names[lastProperty.type]); if (lastProperty.type == 16) //PLY_LIST lastElement.isList = true; lastElement.properties.push_back(lastProperty); ++lastElement.propertiesCount; } //if we have a "mesh-like" element if (lastElement.isList) { //we store its properties in 'listProperties' for (size_t i=0; i<lastElement.properties.size(); ++i) { plyProperty& prop = lastElement.properties[i]; prop.elemIndex = (int)meshElements.size(); //we only keep track of lists (we can't handle per triangle scalars) if (prop.type == 16) listProperties.push_back(prop); else { ccLog::Warning("[PLY] Unhandled property: [%s:%s] (%s)", lastElement.elementName, prop.propName, e_ply_type_names[prop.type]); } } meshElements.push_back(lastElement); } else //else if we have a "point-like" element { //we store its properties in 'stdProperties' for (size_t i=0; i<lastElement.properties.size(); ++i) { plyProperty& prop = lastElement.properties[i]; prop.elemIndex = (int)pointElements.size(); stdProperties.push_back(prop); } pointElements.push_back(lastElement); } } //We need some points at least! if (pointElements.empty()) { ply_close(ply); return CC_FERR_NO_LOAD; } /**********************/ /*** Objects info ***/ /**********************/ { const char* lastObjInfo = NULL; while ((lastObjInfo = ply_get_next_obj_info(ply, lastObjInfo))) ccLog::Print("[PLY][Info] %s",lastObjInfo); } /****************/ /*** Dialog ***/ /****************/ //properties indexes (0 = unassigned) static const unsigned nStdProp = 10; int stdPropIndexes[nStdProp] = {0,0,0,0,0,0,0,0,0,0}; int& xIndex = stdPropIndexes[0]; int& yIndex = stdPropIndexes[1]; int& zIndex = stdPropIndexes[2]; int& nxIndex = stdPropIndexes[3]; int& nyIndex = stdPropIndexes[4]; int& nzIndex = stdPropIndexes[5]; int& rIndex = stdPropIndexes[6]; int& gIndex = stdPropIndexes[7]; int& bIndex = stdPropIndexes[8]; int& iIndex = stdPropIndexes[9]; std::vector<int> sfPropIndexes; //int& sfIndex = stdPropIndexes[10]; static const unsigned nListProp = 2; int listPropIndexes[nListProp] = {0,0}; int& facesIndex = listPropIndexes[0]; int& texCoordsIndex = listPropIndexes[1]; //Combo box items for standard properties (coordinates, color components, etc.) QStringList stdPropsText; stdPropsText << QString("None"); { for (int i=1; i<=static_cast<int>(stdProperties.size()); ++i) { plyProperty& pp = stdProperties[i-1]; QString itemText = QString("%1 - %2 [%3]").arg(pointElements[pp.elemIndex].elementName).arg(pp.propName).arg(e_ply_type_names[pp.type]); assert(pp.type!=16); //we don't want any PLY_LIST here stdPropsText << itemText; QString elementName = QString(pointElements[pp.elemIndex].elementName).toUpper(); QString propName = QString(pp.propName).toUpper(); if (nxIndex == 0 && (propName.contains("NX") || (elementName.contains("NORM") && propName.endsWith("X")))) nxIndex = i; else if (nyIndex == 0 && (propName.contains("NY") || (elementName.contains("NORM") && propName.endsWith("Y")))) nyIndex = i; else if (nzIndex == 0 && (propName.contains("NZ") || (elementName.contains("NORM") && propName.endsWith("Z")))) nzIndex = i; else if (rIndex == 0 && (propName.contains("RED") || (elementName.contains("COL") && propName.endsWith("R")))) rIndex = i; else if (gIndex == 0 && (propName.contains("GREEN") || (elementName.contains("COL") && propName.endsWith("G")))) gIndex = i; else if (bIndex == 0 && (propName.contains("BLUE") || (elementName.contains("COL") && propName.endsWith("B")))) bIndex = i; else if (iIndex == 0 && (propName.contains("INTENSITY") || propName.contains("GRAY") || propName.contains("GREY") || (elementName.contains("COL") && propName.endsWith("I")))) iIndex = i; else if (elementName.contains("VERT") || elementName.contains("POINT")) { if (propName.contains("SCAL")) sfPropIndexes.push_back(i); else if (xIndex == 0 && propName.endsWith("X")) xIndex = i; else if (yIndex == 0 && propName.endsWith("Y")) yIndex = i; else if (zIndex == 0 && propName.endsWith("Z")) zIndex = i; } else if (propName.contains("SCAL") || propName.contains("VAL")) sfPropIndexes.push_back(i); } } //Combo box items for list properties (vertex indexes, etc.) QStringList listPropsText; { listPropsText << QString("None"); for (int i=0; i<static_cast<int>(listProperties.size()); ++i) { plyProperty& pp = listProperties[i]; QString itemText = QString("%0 - %1 [%2]").arg(meshElements[pp.elemIndex].elementName).arg(pp.propName).arg(e_ply_type_names[pp.type]); assert(pp.type==16); //we only want PLY_LIST here listPropsText << itemText; QString elementName = QString(meshElements[pp.elemIndex].elementName).toUpper(); QString propName = QString(pp.propName).toUpper(); if (elementName.contains("FACE") || elementName.contains("TRI")) { if (facesIndex == 0 && propName.contains("IND")) facesIndex = i+1; if (texCoordsIndex == 0 && propName.contains("COORD")) texCoordsIndex = i+1; } } } //combo-box max visible items int stdPropsCount = stdPropsText.count(); int listPropsCount = listPropsText.count(); //we need at least 2 coordinates! if (stdPropsCount < 2) { ccLog::Warning("[PLY] This ply file has less than 2 properties defined! (not even X and Y ;)"); return CC_FERR_MALFORMED_FILE; } else if (stdPropsCount < 4 && !parameters.alwaysDisplayLoadDialog) { //brute force heuristic xIndex = 1; yIndex = 2; zIndex = (stdPropsCount > 3 ? 3 : 0); facesIndex = (listPropsCount > 1 ? 1 : 0); } else { //we count all assigned properties int assignedStdProperties = 0; { for (unsigned i=0; i<nStdProp; ++i) if (stdPropIndexes[i] > 0) ++assignedStdProperties; } int assignedListProperties = 0; { for (unsigned i=0; i<nListProp; ++i) if (listPropIndexes[i] > 0) ++assignedListProperties; } if ( parameters.alwaysDisplayLoadDialog || stdPropsCount > assignedStdProperties+1 //+1 because of the first item in the combo box ('none') || listPropsCount > assignedListProperties+1 ) //+1 because of the first item in the combo box ('none') { PlyOpenDlg pod/*(MainWindow::TheInstance())*/; pod.plyTypeEdit->setText(e_ply_storage_mode_names[storage_mode]); pod.elementsEdit->setText(QString::number(pointElements.size())); pod.propertiesEdit->setText(QString::number(listProperties.size()+stdProperties.size())); //we fill all combo-boxes with all items pod.setDefaultComboItems(stdPropsText); pod.setListComboItems(listPropsText); //try to restore previous context (if any) bool hasAPreviousContext = false; if (!pod.restorePreviousContext(hasAPreviousContext)) { if (hasAPreviousContext) ccLog::Warning("[PLY] Too many differences with the previous file, we reset the dialog."); //Set default/guessed element pod.xComboBox->setCurrentIndex(xIndex); pod.yComboBox->setCurrentIndex(yIndex); pod.zComboBox->setCurrentIndex(zIndex); pod.rComboBox->setCurrentIndex(rIndex); pod.gComboBox->setCurrentIndex(gIndex); pod.bComboBox->setCurrentIndex(bIndex); pod.iComboBox->setCurrentIndex(iIndex); pod.sfComboBox->setCurrentIndex(sfPropIndexes.empty() ? 0 : sfPropIndexes.front()); for (size_t j=1; j<sfPropIndexes.size(); ++j) pod.addSFComboBox(sfPropIndexes[j]); pod.nxComboBox->setCurrentIndex(nxIndex); pod.nyComboBox->setCurrentIndex(nyIndex); pod.nzComboBox->setCurrentIndex(nzIndex); pod.facesComboBox->setCurrentIndex(facesIndex); pod.textCoordsComboBox->setCurrentIndex(texCoordsIndex); } //We show the dialog (or we try to skip it ;) if (parameters.alwaysDisplayLoadDialog && !pod.canBeSkipped() && !pod.exec()) { ply_close(ply); return CC_FERR_CANCELED_BY_USER; } //Force events processing (to hide dialog) QCoreApplication::processEvents(); xIndex = pod.xComboBox->currentIndex(); yIndex = pod.yComboBox->currentIndex(); zIndex = pod.zComboBox->currentIndex(); nxIndex = pod.nxComboBox->currentIndex(); nyIndex = pod.nyComboBox->currentIndex(); nzIndex = pod.nzComboBox->currentIndex(); rIndex = pod.rComboBox->currentIndex(); gIndex = pod.gComboBox->currentIndex(); bIndex = pod.bComboBox->currentIndex(); iIndex = pod.iComboBox->currentIndex(); facesIndex = pod.facesComboBox->currentIndex(); texCoordsIndex = pod.textCoordsComboBox->currentIndex(); //get (non null) SF properties sfPropIndexes.clear(); { for (size_t j=0; j<pod.m_sfCombos.size(); ++j) if (pod.m_sfCombos[j]->currentIndex() > 0) sfPropIndexes.push_back(pod.m_sfCombos[j]->currentIndex()); } } } /*************************/ /*** Callbacks setup ***/ /*************************/ //Main point cloud ccPointCloud* cloud = new ccPointCloud("unnamed - Cloud"); /* POINTS (X,Y,Z) */ unsigned numberOfPoints = 0; assert(xIndex != yIndex && xIndex != zIndex && yIndex != zIndex); //POINTS (X) if (xIndex > 0) { long flags = ELEM_POS_0; //X coordinate if (xIndex > yIndex && xIndex > zIndex) flags |= ELEM_EOL; plyProperty& pp = stdProperties[xIndex-1]; ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, vertex_cb, cloud, flags); numberOfPoints = pointElements[pp.elemIndex].elementInstances; } //POINTS (Y) if (yIndex > 0) { long flags = ELEM_POS_1; //Y coordinate if (yIndex > xIndex && yIndex > zIndex) flags |= ELEM_EOL; plyProperty& pp = stdProperties[yIndex-1]; ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, vertex_cb, cloud, flags); if (numberOfPoints > 0) { if ((long)numberOfPoints != pointElements[pp.elemIndex].elementInstances) { ccLog::Warning("[PLY] Bad/uncompatible assignation of point properties!"); delete cloud; ply_close(ply); return CC_FERR_BAD_ENTITY_TYPE; } } else numberOfPoints = pointElements[pp.elemIndex].elementInstances; } //POINTS (Z) if (zIndex > 0) { long flags = ELEM_POS_2; //Z coordinate if (zIndex > xIndex && zIndex > yIndex) flags |= ELEM_EOL; plyProperty& pp = stdProperties[zIndex-1]; ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, vertex_cb, cloud, flags); if (numberOfPoints > 0) { if ((long)numberOfPoints != pointElements[pp.elemIndex].elementInstances) { ccLog::Warning("[PLY] Bad/uncompatible assignation of point properties!"); delete cloud; ply_close(ply); return CC_FERR_BAD_ENTITY_TYPE; } } else numberOfPoints = pointElements[pp.elemIndex].elementInstances; } if (numberOfPoints == 0 || !cloud->reserveThePointsTable(numberOfPoints)) { delete cloud; ply_close(ply); return CC_FERR_NOT_ENOUGH_MEMORY; } /* NORMALS (X,Y,Z) */ unsigned numberOfNormals=0; assert(nxIndex == 0 || (nxIndex != nyIndex && nxIndex != nzIndex)); assert(nyIndex == 0 || (nyIndex != nxIndex && nyIndex != nzIndex)); assert(nzIndex == 0 || (nzIndex != nxIndex && nzIndex != nyIndex)); //NORMALS (X) if (nxIndex > 0) { long flags = ELEM_POS_0; //Nx if (nxIndex > nyIndex && nxIndex > nzIndex) flags |= ELEM_EOL; plyProperty& pp = stdProperties[nxIndex-1]; ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, normal_cb, cloud, flags); numberOfNormals = pointElements[pp.elemIndex].elementInstances; } //NORMALS (Y) if (nyIndex > 0) { long flags = ELEM_POS_1; //Ny if (nyIndex > nxIndex && nyIndex > nzIndex) flags |= ELEM_EOL; plyProperty& pp = stdProperties[nyIndex-1]; ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, normal_cb, cloud, flags); numberOfNormals = std::max(numberOfNormals, (unsigned)pointElements[pp.elemIndex].elementInstances); } //NORMALS (Z) if (nzIndex > 0) { long flags = ELEM_POS_2; //Nz if (nzIndex > nxIndex && nzIndex > nyIndex) flags |= ELEM_EOL; plyProperty& pp = stdProperties[nzIndex-1]; ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, normal_cb, cloud, flags); numberOfNormals = std::max(numberOfNormals, (unsigned)pointElements[pp.elemIndex].elementInstances); } //We check that the number of normals corresponds to the number of points if (numberOfNormals > 0) { if (numberOfPoints != numberOfNormals) { ccLog::Warning("[PLY] The number of normals doesn't match the number of points!"); delete cloud; ply_close(ply); return CC_FERR_BAD_ENTITY_TYPE; } if (!cloud->reserveTheNormsTable()) { delete cloud; ply_close(ply); return CC_FERR_NOT_ENOUGH_MEMORY; } cloud->showNormals(true); } /* COLORS (R,G,B) */ unsigned numberOfColors=0; assert(rIndex == 0 || (rIndex != gIndex && rIndex != bIndex)); assert(gIndex == 0 || (gIndex != rIndex && gIndex != bIndex)); assert(bIndex == 0 || (bIndex != rIndex && bIndex != gIndex)); if (rIndex > 0) { long flags = ELEM_POS_0; //R if (rIndex > gIndex && rIndex > bIndex) flags |= ELEM_EOL; plyProperty& pp = stdProperties[rIndex-1]; ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, rgb_cb, cloud, flags); numberOfColors = pointElements[pp.elemIndex].elementInstances; } if (gIndex > 0) { long flags = ELEM_POS_1; //G if (gIndex > rIndex && gIndex > bIndex) flags |= ELEM_EOL; plyProperty& pp = stdProperties[gIndex-1]; ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, rgb_cb, cloud, flags); numberOfColors = std::max(numberOfColors, (unsigned)pointElements[pp.elemIndex].elementInstances); } if (bIndex > 0) { long flags = ELEM_POS_2; //B if (bIndex > rIndex && bIndex > gIndex) flags |= ELEM_EOL; plyProperty& pp = stdProperties[bIndex-1]; ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, rgb_cb, cloud, flags); numberOfColors = std::max(numberOfColors, (unsigned)pointElements[pp.elemIndex].elementInstances); } /* Intensity (I) */ //INTENSITE (G) if (iIndex > 0) { if (numberOfColors > 0) { ccLog::Error("Can't import colors AND intensity (intensities will be ignored)!"); ccLog::Warning("[PLY] intensities will be ignored"); } else { plyProperty pp = stdProperties[iIndex-1]; ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, grey_cb, cloud, 0); numberOfColors = pointElements[pp.elemIndex].elementInstances; } } //We check that the number of colors corresponds to the number of points if (numberOfColors > 0) { if (numberOfPoints != numberOfColors) { ccLog::Warning("The number of colors doesn't match the number of points!"); delete cloud; ply_close(ply); return CC_FERR_BAD_ENTITY_TYPE; } if (!cloud->reserveTheRGBTable()) { delete cloud; ply_close(ply); return CC_FERR_NOT_ENOUGH_MEMORY; } cloud->showColors(true); } /* SCALAR FIELDS (SF) */ { for (size_t i=0; i<sfPropIndexes.size(); ++i) { int sfIndex = sfPropIndexes[i]; plyProperty& pp = stdProperties[sfIndex-1]; unsigned numberOfScalars = pointElements[pp.elemIndex].elementInstances; //does the number of scalars matches the number of points? if (numberOfPoints != numberOfScalars) { ccLog::Error(QString("Scalar field #%1: the number of scalars doesn't match the number of points (they will be ignored)!").arg(i+1)); ccLog::Warning(QString("[PLY] Scalar field #%1 ignored!").arg(i+1)); numberOfScalars = 0; } else { QString qPropName(pp.propName); if (qPropName.startsWith("scalar_") && qPropName.length() > 7) { //remove the 'scalar_' prefix added when saving SF with CC! qPropName = qPropName.mid(7).replace('_',' '); } int sfIdx = cloud->addScalarField(qPrintable(qPropName)); if (sfIdx >= 0) { CCLib::ScalarField* sf = cloud->getScalarField(sfIdx); assert(sf); if (sf->reserve(numberOfScalars)) { ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, scalar_cb, sf, 1); } else { cloud->deleteScalarField(sfIdx); sfIdx = -1; } } if (sfIdx < 0) { ccLog::Error(QString("Scalar field #%1: not enough memory to load scalar field (they will be ignored)!").arg(i+1)); ccLog::Warning(QString("[PLY] Scalar field #%1 ignored!").arg(i+1)); } } } } /* MESH FACETS (TRI) */ ccMesh* mesh = 0; unsigned numberOfFacets = 0; if (facesIndex > 0) { plyProperty& pp = listProperties[facesIndex-1]; assert(pp.type==16); //we only accept PLY_LIST here! mesh = new ccMesh(cloud); numberOfFacets = meshElements[pp.elemIndex].elementInstances; if (!mesh->reserve(numberOfFacets)) { ccLog::Error("Not enough memory to load facets (they will be ignored)!"); ccLog::Warning("[PLY] Mesh ignored!"); delete mesh; mesh = 0; numberOfFacets = 0; } else { ply_set_read_cb(ply, meshElements[pp.elemIndex].elementName, pp.propName, face_cb, mesh, 0); } } if (texCoordsIndex > 0) { plyProperty& pp = listProperties[texCoordsIndex-1]; assert(pp.type == 16); //we only accept PLY_LIST here! texCoords = new TextureCoordsContainer(); texCoords->link(); long numberOfCoordinates = meshElements[pp.elemIndex].elementInstances; assert(numberOfCoordinates == numberOfFacets); if (!texCoords->reserve(numberOfCoordinates*3)) { ccLog::Error("Not enough memory to load texture coordinates (they will be ignored)!"); ccLog::Warning("[PLY] Texture coordinates ignored!"); texCoords->release(); texCoords = 0; } else { ply_set_read_cb(ply, meshElements[pp.elemIndex].elementName, pp.propName, texCoords_cb, texCoords, 0); } } ccProgressDialog pDlg(false); if (parameters.alwaysDisplayLoadDialog) { //pDlg.setInfo("Loading in progress..."); //pDlg.setMethodTitle("PLY file"); pDlg.setInfo("正在加载..."); pDlg.setMethodTitle("PLY 文件"); pDlg.setRange(0,0); pDlg.show(); QApplication::processEvents(); } //let 'Rply' do the job;) int success = 0; try { success = ply_read(ply); } catch(...) { success = -1; } ply_close(ply); if (success < 1) { if (mesh) delete mesh; delete cloud; return CC_FERR_READING; } //we check mesh if (mesh && mesh->size() == 0) { if (s_unsupportedPolygonType) ccLog::Error("Mesh is not triangular! (unsupported)"); else ccLog::Error("Mesh is empty!"); delete mesh; mesh=0; } if (texCoords && (s_invalidTexCoordinates || s_texCoordCount != 3*mesh->size())) { ccLog::Error("Invalid texture coordinates! (they will be ignored)"); texCoords->release(); texCoords=0; } //we save parameters parameters = s_loadParameters; //we update scalar field(s) { for (unsigned i=0; i<cloud->getNumberOfScalarFields(); ++i) { CCLib::ScalarField* sf = cloud->getScalarField(i); assert(sf); sf->computeMinAndMax(); if (i == 0) { cloud->setCurrentDisplayedScalarField(0); cloud->showSF(true); } } } if (mesh) { assert(s_triCount > 0); //check number of loaded facets against 'theoretical' number if (s_triCount<numberOfFacets) { mesh->resize(s_triCount); ccLog::Warning("[PLY] Missing vertex indexes!"); } //check that vertex indices start at 0 unsigned minVertIndex=numberOfPoints,maxVertIndex=0; for (unsigned i=0;i<s_triCount;++i) { const CCLib::TriangleSummitsIndexes* tri = mesh->getTriangleIndexes(i); if (tri->i1 < minVertIndex) minVertIndex = tri->i1; else if (tri->i1 > maxVertIndex) maxVertIndex = tri->i1; if (tri->i2 < minVertIndex) minVertIndex = tri->i2; else if (tri->i2 > maxVertIndex) maxVertIndex = tri->i2; if (tri->i3 < minVertIndex) minVertIndex = tri->i3; else if (tri->i3 > maxVertIndex) maxVertIndex = tri->i3; } if (maxVertIndex>=numberOfPoints) { if (maxVertIndex == numberOfPoints && minVertIndex > 0) { ccLog::Warning("[PLY] Vertex indices seem to be shifted (+1)! We will try to 'unshift' indices (otherwise file is corrupted...)"); for (unsigned i=0;i<s_triCount;++i) { CCLib::TriangleSummitsIndexes* tri = mesh->getTriangleIndexes(i); --tri->i1; --tri->i2; --tri->i3; } } else //file is definitely corrupted! { ccLog::Warning("[PLY] Invalid vertex indices!"); delete mesh; delete cloud; return CC_FERR_MALFORMED_FILE; } } mesh->addChild(cloud); cloud->setEnabled(false); cloud->setName("Vertices"); //cloud->setLocked(true); //DGM: no need to lock it as it is only used by one mesh! //associated texture if (texCoords) { if (!textureFileName.isEmpty()) { QString textureFilePath = QFileInfo(filename).absolutePath() + QString('/') + textureFileName; ccMaterial::Shared material(new ccMaterial(textureFileName)); if (material->loadAndSetTexture(textureFilePath)) { if (mesh->reservePerTriangleTexCoordIndexes() && mesh->reservePerTriangleMtlIndexes()) { const QImage texture = material->getTexture(); ccLog::Print(QString("[PLY][Texture] Successfully loaded texture '%1' (%2x%3 pixels)").arg(textureFileName).arg(texture.width()).arg(texture.height())); //materials ccMaterialSet* materials = new ccMaterialSet("materials"); material->setDiffuse(ccColor::bright); material->setSpecular(ccColor::darker); material->setAmbient(ccColor::darker); materials->push_back(material); mesh->setMaterialSet(materials); mesh->setTexCoordinatesTable(texCoords); for (unsigned i=0;i<mesh->size();++i) { mesh->addTriangleMtlIndex(0); mesh->addTriangleTexCoordIndexes(i*3,i*3+1,i*3+2); } mesh->showMaterials(true); } else { ccLog::Warning("[PLY][Texture] Failed to reserve per-triangle texture coordinates! (not enough memory?)"); } } else { ccLog::Warning(QString("[PLY][Texture] Failed to load texture '%1'").arg(textureFilePath)); } } else { ccLog::Warning("[PLY][Texture] Texture coordinates loaded without an associated image! (we look for the 'TextureFile' keyword in comments)"); } } if (cloud->hasColors()) mesh->showColors(true); if (cloud->hasDisplayedScalarField()) mesh->showSF(true); if (cloud->hasNormals()) mesh->showNormals(true); else { //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!) //mesh->computeNormals(); ccLog::Warning("[PLY] Mesh has no normal! You can manually compute them (select it then call \"Edit > Normals > Compute\")"); } if (mesh->hasMaterials()) mesh->showNormals(false); container.addChild(mesh); } else { container.addChild(cloud); } if (texCoords) { texCoords->release(); texCoords = 0; } return CC_FERR_NO_ERROR; }
CC_FILE_ERROR BinFilter::loadFileV1(QFile& in, ccHObject& container, unsigned nbScansTotal) { if (nbScansTotal>99) { if (QMessageBox::question(0, QString("Oups"), QString("Hum, do you really expect %1 point clouds?").arg(nbScansTotal))==QMessageBox::No) return CC_FERR_WRONG_FILE_TYPE; } else if (nbScansTotal==0) { return CC_FERR_NO_LOAD; } ccProgressDialog pdlg(true); pdlg.setMethodTitle("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); //progress for this cloud CCLib::NormalizedProgress nprogress(&pdlg,nbOfPoints); pdlg.reset(); char buffer[256]; sprintf(buffer,"cloud %i/%i (%i points)",k+1,nbScansTotal,nbOfPoints); pdlg.setInfo(buffer); pdlg.start(); QApplication::processEvents(); if (nbOfPoints==0) { //Console::print("[BinFilter::loadModelFromBinaryFile] rien a faire !\n"); continue; } //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 #%i",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 = ccMin(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(); CCVector3 P; unsigned char C[3]; double D; //does the associated scalar field is negative? bool negSF = false; unsigned lineReaded=0; int parts = 0; //lecture du fichier for (unsigned i=0;i<nbOfPoints;++i) { if (lineReaded == fileChunkPos+fileChunkSize) { if (header.scalarField) loadedCloud->getCurrentInScalarField()->computeMinAndMax(); container.addChild(loadedCloud); fileChunkPos = lineReaded; fileChunkSize = ccMin(nbOfPoints-lineReaded,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(); } if (in.read((char*)P.u,sizeof(float)*3)<0) { //Console::print("[BinFilter::loadModelFromBinaryFile] Error reading the %ith entity point !\n",k); return CC_FERR_READING; } loadedCloud->addPoint(P); if (header.colors) { if (in.read((char*)C,sizeof(colorType)*3)<0) { //Console::print("[BinFilter::loadModelFromBinaryFile] Error reading the %ith entity colors !\n",k); return CC_FERR_READING; } loadedCloud->addRGBColor(C); } if (header.normals) { if (in.read((char*)P.u,sizeof(float)*3)<0) { //Console::print("[BinFilter::loadModelFromBinaryFile] Error reading the %ith entity norms !\n",k); return CC_FERR_READING; } loadedCloud->addNorm(P.u); } if (header.scalarField) { if (in.read((char*)&D,sizeof(double))<0) { //Console::print("[BinFilter::loadModelFromBinaryFile] Error reading the %ith entity distance !\n",k); return CC_FERR_READING; } DistanceType d = (DistanceType)D; //if there are negative values, we test if they are particular values (HIDDEN_VALUE, etc.) //or not particular (in which case we have a non strictly positive SF) if (d<0.0 && !negSF) { //we must test if the value is a particular one if (d != HIDDEN_VALUE && d != OUT_VALUE && d != SEGMENTED_VALUE) negSF = true; } loadedCloud->setPointScalarValue(i,d); } lineReaded++; if (!nprogress.oneStep()) { loadedCloud->resize(i+1-fileChunkPos); k=nbScansTotal; i=nbOfPoints; } } if (header.scalarField) { CCLib::ScalarField* sf = loadedCloud->getCurrentInScalarField(); assert(sf); sf->setName(sfName); sf->setPositive(!negSF); sf->computeMinAndMax(); loadedCloud->setCurrentDisplayedScalarField(loadedCloud->getCurrentInScalarFieldIndex()); loadedCloud->showSF(true); } container.addChild(loadedCloud); } return CC_FERR_NO_ERROR; }