CC_VISIBILITY_TYPE ccGenericPointCloud::testVisibility(const CCVector3& P) { unsigned i=0,childNum=getChildrenNumber(); CC_VISIBILITY_TYPE nvt, vt = ALL; while (i<childNum && vt==VIEWED) { if (m_children[i]->isKindOf(CC_SENSOR)) { nvt = static_cast<ccSensor*>(m_children[i])->checkVisibility(P); vt = ccMin(vt,nvt); } ++i; } return (vt==ALL ? VIEWED : vt); }
CC_FILE_ERROR PVFilter::loadFile(const char* filename, ccHObject& container, bool alwaysDisplayLoadDialog/*=true*/, bool* coordinatesShiftEnabled/*=0*/, double* coordinatesShift/*=0*/) { //ccConsole::Print("[PVFilter::loadFile] Opening binary file '%s'...\n",filename); //opening file FILE *fp = fopen(filename, "rb"); if (!fp) return CC_FERR_NO_ERROR; CCLib::CCMiscTools::fseek64(fp,0,2); //we reach the end of the file __int64 fileSize = CCLib::CCMiscTools::ftell64(fp); //file size query CCLib::CCMiscTools::fseek64(fp,0,0); //back to the begining //we read the points number unsigned nbOfPoints = (unsigned) (fileSize / (__int64)(4*sizeof(float))); //ccConsole::Print("[PVFilter::loadFile] Points: %i\n",nbOfPoints); //if the file is too big, it will be chuncked in multiple parts unsigned fileChunkPos = 0; unsigned fileChunkSize = ccMin(nbOfPoints,CC_MAX_NUMBER_OF_POINTS_PER_CLOUD); //new cloud char name[64],k=0; sprintf(name,"unnamed - Cloud #%i",k); ccPointCloud* loadedCloud = new ccPointCloud(name); loadedCloud->reserveThePointsTable(fileChunkSize); loadedCloud->enableScalarField(); float rBuff[3]; //progress dialog ccProgressDialog pdlg(true); //cancel available CCLib::NormalizedProgress nprogress(&pdlg,nbOfPoints); pdlg.setMethodTitle("Open PV file"); char buffer[256]; sprintf(buffer,"Points: %u",nbOfPoints); pdlg.setInfo(buffer); pdlg.start(); //number of points read from the begining of the current cloud part //WARNING: different from lineCounter unsigned pointsRead=0; for (unsigned i=0;i<nbOfPoints;i++) { //if we reach the max. cloud size limit, we cerate a new chunk if (pointsRead == fileChunkPos+fileChunkSize) { loadedCloud->getCurrentInScalarField()->computeMinAndMax(); int sfIdx = loadedCloud->getCurrentInScalarFieldIndex(); loadedCloud->setCurrentDisplayedScalarField(sfIdx); loadedCloud->showSF(sfIdx>=0); container.addChild(loadedCloud); fileChunkPos = pointsRead; fileChunkSize = ccMin(nbOfPoints-pointsRead,CC_MAX_NUMBER_OF_POINTS_PER_CLOUD); sprintf(name,"unnamed - Cloud #%i",++k); loadedCloud = new ccPointCloud(name); loadedCloud->reserveThePointsTable(fileChunkSize); loadedCloud->enableScalarField(); } //we read the 3 coordinates of the point if (fread(rBuff,4,3,fp)>=0) { //conversion to CCVector3 CCVector3 P = CCVector3(PointCoordinateType(rBuff[0]), PointCoordinateType(rBuff[1]), PointCoordinateType(rBuff[2])); loadedCloud->addPoint(P); } else { fclose(fp); return CC_FERR_NO_ERROR; } //then the scalar value if (fread(rBuff,4,1,fp)>=0) { //conversion to DistanceType DistanceType d = DistanceType(rBuff[0]); loadedCloud->setPointScalarValue(pointsRead,d); } else { fclose(fp); return CC_FERR_NO_ERROR; } ++pointsRead; if (!nprogress.oneStep()) { loadedCloud->resize(i+1-fileChunkPos); break; } } loadedCloud->getCurrentInScalarField()->computeMinAndMax(); int sfIdx = loadedCloud->getCurrentInScalarFieldIndex(); loadedCloud->setCurrentDisplayedScalarField(sfIdx); loadedCloud->showSF(sfIdx>=0); container.addChild(loadedCloud); fclose(fp); return CC_FERR_NO_ERROR; }
CC_FILE_ERROR LASFilter::loadFile(const char* filename, ccHObject& container, bool alwaysDisplayLoadDialog/*=true*/, bool* coordinatesShiftEnabled/*=0*/, double* coordinatesShift/*=0*/) { //opening file std::ifstream ifs; ifs.open(filename, std::ios::in | std::ios::binary); if (ifs.fail()) return CC_FERR_READING; liblas::Reader* reader = 0; unsigned nbOfPoints = 0; std::vector<std::string> dimensions; try { reader = new liblas::Reader(liblas::ReaderFactory().CreateWithStream(ifs)); //using factory for automatic and transparent //handling of compressed/uncompressed files liblas::Header const& header = reader->GetHeader(); #ifdef _DEBUG //ccConsole::Print("[LAS FILE] %s - signature: %s",filename,header.GetFileSignature().c_str()); #endif //get fields present in file dimensions = header.GetSchema().GetDimensionNames(); //and of course the number of points nbOfPoints = header.GetPointRecordsCount(); } catch (...) { delete reader; ifs.close(); return CC_FERR_READING; } if (nbOfPoints==0) { //strange file ;) delete reader; ifs.close(); return CC_FERR_NO_LOAD; } liblas::Color rgbColorMask; //(0,0,0) on construction bool hasClassif = false; bool hasIntensity = false; bool hasTime = false; bool hasReturnNumber = false; for (unsigned k=0;k<dimensions.size();++k) { QString dim = QString(dimensions[k].c_str()).toUpper(); bool handled=true; if (dim == "RED") rgbColorMask.SetRed(~0); else if (dim == "BLUE") rgbColorMask.SetBlue(~0); else if (dim == "GREEN") rgbColorMask.SetGreen(~0); else if (dim == "CLASSIFICATION") hasClassif=true; else if (dim == "TIME") hasTime=true; else if (dim == "INTENSITY") hasIntensity=true; else if (dim == "RETURN NUMBER") hasReturnNumber=true; else if (dim != "X" && dim != "Y" && dim != "Z") handled=false; ccConsole::Print(QString("[LAS FILE] Found dimension '%1' (%2)").arg(dimensions[k].c_str()).arg(handled ? "handled" : "not handled")); } bool hasColor = (rgbColorMask[0] || rgbColorMask[1] || rgbColorMask[2]); //progress dialog ccProgressDialog pdlg(true); //cancel available CCLib::NormalizedProgress nprogress(&pdlg,nbOfPoints); pdlg.setMethodTitle("Open LAS file"); pdlg.setInfo(qPrintable(QString("Points: %1").arg(nbOfPoints))); pdlg.start(); //number of points read from the begining of the current cloud part unsigned pointsRead=0; double Pshift[3]={0.0,0.0,0.0}; //by default we read color as 8 bits integers and we will change this to 16 bits if it's not (16 bits is the standard!) unsigned char colorCompBitDec = 0; colorType rgb[3]={0,0,0}; ccPointCloud* loadedCloud=0; ccScalarField* classifSF=0; uint8_t firstClassifValue=0; ccScalarField* timeSF=0; double firstTime=0.0; ccScalarField* intensitySF=0; uint16_t firstIntensity=0; ccScalarField* returnNumberSF=0; uint16_t firstReturnNumber=0; //if the file is too big, we will chunck it in multiple parts unsigned int fileChunkPos = 0; unsigned int fileChunkSize = 0; while (true) { //if we reach the end of the file, or the max. cloud size limit (in which case we cerate a new chunk) bool newPointAvailable = (nprogress.oneStep() && reader->ReadNextPoint()); if (!newPointAvailable || pointsRead == fileChunkPos+fileChunkSize) { if (loadedCloud) { if (loadedCloud->size()) { bool thisChunkHasColors = loadedCloud->hasColors(); loadedCloud->showColors(thisChunkHasColors); if (hasColor && !thisChunkHasColors) ccLog::Warning("[LAS FILE] Color field was all black! We ignored it..."); if (hasClassif) { if (classifSF) { classifSF->computeMinAndMax(); int cMin = (int)classifSF->getMin(); int cMax = (int)classifSF->getMax(); classifSF->setColorRampSteps(cMax-cMin); //classifSF->setMinSaturation(cMin); int sfIndex = loadedCloud->addScalarField(classifSF); if (!loadedCloud->hasDisplayedScalarField()) { loadedCloud->setCurrentDisplayedScalarField(sfIndex); loadedCloud->showSF(!thisChunkHasColors); } } else ccLog::Warning(QString("[LAS FILE] All classification values were the same (%1)! We ignored them...").arg(firstClassifValue)); } if (hasIntensity) { if (intensitySF) { intensitySF->computeMinAndMax(); intensitySF->setColorRamp(GREY); int sfIndex = loadedCloud->addScalarField(intensitySF); if (!loadedCloud->hasDisplayedScalarField()) { loadedCloud->setCurrentDisplayedScalarField(sfIndex); loadedCloud->showSF(!thisChunkHasColors); } } else ccLog::Warning(QString("[LAS FILE] All intensities were the same (%1)! We ignored them...").arg(firstIntensity)); } if (hasTime) { if (timeSF) { timeSF->computeMinAndMax(); int sfIndex = loadedCloud->addScalarField(timeSF); if (!loadedCloud->hasDisplayedScalarField()) { loadedCloud->setCurrentDisplayedScalarField(sfIndex); loadedCloud->showSF(!thisChunkHasColors); } } else ccLog::Warning(QString("[LAS FILE] All timestamps were the same (%1)! We ignored them...").arg(firstTime)); } if (hasReturnNumber) { if (returnNumberSF) { returnNumberSF->computeMinAndMax(); int rMin = (int)returnNumberSF->getMin(); int rMax = (int)returnNumberSF->getMax(); returnNumberSF->setColorRampSteps(rMax-rMin); int sfIndex = loadedCloud->addScalarField(returnNumberSF); if (!loadedCloud->hasDisplayedScalarField()) { loadedCloud->setCurrentDisplayedScalarField(sfIndex); loadedCloud->showSF(!thisChunkHasColors); } } else ccLog::Warning(QString("[LAS FILE] All return numbers were the same (%1)! We ignored them...").arg(firstReturnNumber)); } //if we have reserved too much memory if (loadedCloud->size() < loadedCloud->capacity()) loadedCloud->resize(loadedCloud->size()); QString chunkName("unnamed - Cloud"); unsigned n = container.getChildrenNumber(); if (n!=0) //if we have more than one cloud, we append an index { if (n==1) //we must also update the first one! container.getChild(0)->setName(chunkName+QString(" #1")); chunkName += QString(" #%1").arg(n+1); } loadedCloud->setName(chunkName); container.addChild(loadedCloud); loadedCloud=0; } else { //empty cloud?! delete loadedCloud; loadedCloud=0; } if (classifSF) classifSF->release(); classifSF=0; if (intensitySF) intensitySF->release(); intensitySF=0; if (returnNumberSF) returnNumberSF->release(); returnNumberSF=0; if (timeSF) timeSF->release(); timeSF=0; } if (!newPointAvailable) break; //end of the file (or cancel requested) //otherwise, we must create a new cloud fileChunkPos = pointsRead; fileChunkSize = ccMin(nbOfPoints-pointsRead,CC_MAX_NUMBER_OF_POINTS_PER_CLOUD); loadedCloud = new ccPointCloud(); if (!loadedCloud->reserveThePointsTable(fileChunkSize)) { ccLog::Warning("[LASFilter::loadFile] Not enough memory!"); delete loadedCloud; delete reader; ifs.close(); return CC_FERR_NOT_ENOUGH_MEMORY; } loadedCloud->setOriginalShift(Pshift[0],Pshift[1],Pshift[2]); //DGM: from now on, we only enable scalar fields when we detect a valid value! if (hasClassif) { assert(!classifSF); firstClassifValue = 0; } if (hasTime) { assert(!timeSF); firstTime = 0.0; } if (hasIntensity) { assert(!intensitySF); firstIntensity=0; } if (hasReturnNumber) { assert(!returnNumberSF); firstReturnNumber = 0; } } assert(newPointAvailable); const liblas::Point& p = reader->GetPoint(); //first point: check for 'big' coordinates if (pointsRead==0) { double P[3]={p.GetX(),p.GetY(),p.GetZ()}; bool shiftAlreadyEnabled = (coordinatesShiftEnabled && *coordinatesShiftEnabled && coordinatesShift); if (shiftAlreadyEnabled) memcpy(Pshift,coordinatesShift,sizeof(double)*3); bool applyAll=false; if (ccCoordinatesShiftManager::Handle(P,0,alwaysDisplayLoadDialog,shiftAlreadyEnabled,Pshift,0,applyAll)) { loadedCloud->setOriginalShift(Pshift[0],Pshift[1],Pshift[2]); ccConsole::Warning("[LASFilter::loadFile] Cloud has been recentered! Translation: (%.2f,%.2f,%.2f)",Pshift[0],Pshift[1],Pshift[2]); //we save coordinates shift information if (applyAll && coordinatesShiftEnabled && coordinatesShift) { *coordinatesShiftEnabled = true; coordinatesShift[0] = Pshift[0]; coordinatesShift[1] = Pshift[1]; coordinatesShift[2] = Pshift[2]; } } } CCVector3 P(p.GetX()+Pshift[0],p.GetY()+Pshift[1],p.GetZ()+Pshift[2]); loadedCloud->addPoint(P); //color field if (hasColor) { //Warning: LAS colors are stored on 16 bits! liblas::Color col = p.GetColor(); col[0] &= rgbColorMask[0]; col[1] &= rgbColorMask[1]; col[2] &= rgbColorMask[2]; //if we don't have reserved a color field yet, we check first that color is not black bool pushColor = true; if (!loadedCloud->hasColors()) { //if the color is not black, we are sure it's a valid color field! if (col[0] || col[1] || col[2]) { if (loadedCloud->reserveTheRGBTable()) { //we must set the color (black) of all the precedently skipped points for (unsigned i=0;i<loadedCloud->size()-1;++i) loadedCloud->addRGBColor(ccColor::black); } else { ccConsole::Warning("[LAS FILE] Not enough memory: color field will be ignored!"); hasColor = false; //no need to retry with the other chunks anyway pushColor = false; } } else //otherwise we ignore it for the moment (we'll add it later if necessary) { pushColor = false; } } //do we need to push this color? if (pushColor) { //we test if the color components are on 16 bits (standard) or only on 8 bits (it happens ;) if (colorCompBitDec==0) { if ( (col[0] & 0xFF00) || (col[1] & 0xFF00) || (col[2] & 0xFF00)) { //the color components are on 16 bits! ccLog::Print("[LAS FILE] Color components are coded on 16 bits"); colorCompBitDec = 8; //we fix all the precedently read colors for (unsigned i=0;i<loadedCloud->size()-1;++i) loadedCloud->setPointColor(i,ccColor::black); //255 >> 8 = 0! } } rgb[0]=(colorType)(col[0]>>colorCompBitDec); rgb[1]=(colorType)(col[1]>>colorCompBitDec); rgb[2]=(colorType)(col[2]>>colorCompBitDec); loadedCloud->addRGBColor(rgb); } } if (hasClassif) { uint8_t intValue = p.GetClassification().GetClass(); if (classifSF) { classifSF->addElement(intValue); } else { //first point? we track its value if (loadedCloud->size()==1) { firstClassifValue = intValue; } else if (intValue != firstClassifValue) { classifSF = new ccScalarField(CC_LAS_CLASSIFICATION_FIELD_NAME,true); if (classifSF->reserve(fileChunkSize)) { classifSF->link(); //we must set the classification value (firstClassifValue) of all the precedently skipped points for (unsigned i=0;i<loadedCloud->size()-1;++i) classifSF->addElement(firstClassifValue); classifSF->addElement(intValue); } else { ccConsole::Warning("[LAS FILE] Not enough memory: classificaiton field will be ignored!"); hasClassif = false; //no need to retry with the other chunks anyway classifSF->release(); classifSF=0; } } } } if (hasTime) { double timeValue = p.GetTime(); if (timeSF) { timeSF->addElement(timeValue); } else { //first point? we track its value if (loadedCloud->size()==1) { firstTime = timeValue; } else if (timeValue != firstIntensity) { timeSF = new ccScalarField("Time",true); if (timeSF->reserve(fileChunkSize)) { timeSF->link(); //we must set the timestamp value (firstTime) of all the precedently skipped points for (unsigned i=0;i<loadedCloud->size()-1;++i) timeSF->addElement(firstTime); timeSF->addElement(timeValue); } else { ccConsole::Warning("[LAS FILE] Not enough memory: 'time' field will be ignored!"); hasTime = false; //no need to retry with the other chunks anyway timeSF->release(); timeSF=0; } } } } if (hasIntensity) { uint16_t intValue = p.GetIntensity(); if (intensitySF) { intensitySF->addElement(intValue); } else { //first point? we track its value if (loadedCloud->size()==1) { firstIntensity = intValue; } else if (intValue != firstIntensity) { intensitySF = new ccScalarField("Intensity",true); if (intensitySF->reserve(fileChunkSize)) { intensitySF->link(); //we must set the intensity (firstIntensity) of all the precedently skipped points for (unsigned i=0;i<loadedCloud->size()-1;++i) intensitySF->addElement(firstIntensity); intensitySF->addElement(intValue); } else { ccConsole::Warning("[LAS FILE] Not enough memory: intensity field will be ignored!"); hasIntensity = false; //no need to retry with the other chunks anyway intensitySF->release(); intensitySF=0; } } } } if (hasReturnNumber) { uint16_t intValue = p.GetReturnNumber(); if (returnNumberSF) { returnNumberSF->addElement(intValue); } else { //first point? we track its value if (loadedCloud->size()==1) { firstReturnNumber = intValue; } else if (intValue != firstReturnNumber) { returnNumberSF = new ccScalarField("Return number",true); if (returnNumberSF->reserve(fileChunkSize)) { returnNumberSF->link(); //we must set the return index (firstReturnNumber) of all the precedently skipped points for (unsigned i=0;i<loadedCloud->size()-1;++i) returnNumberSF->addElement(firstReturnNumber); returnNumberSF->addElement(intValue); } else { ccConsole::Warning("[LAS FILE] Not enough memory: return number field will be ignored!"); hasReturnNumber = false; //no need to retry with the other chunks anyway returnNumberSF->release(); returnNumberSF=0; } } } } ++pointsRead; } if (reader) delete reader; reader=0; ifs.close(); 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; }