bool ccGenericMesh::computeNormals() { if (!m_associatedCloud || !m_associatedCloud->isA(CC_POINT_CLOUD)) //TODO return false; unsigned triCount = size(); if (triCount==0) { ccLog::Error("[ccGenericMesh::computeNormals] Empty mesh!"); return false; } unsigned vertCount=m_associatedCloud->size(); if (vertCount<3) { ccLog::Error("[ccGenericMesh::computeNormals] Not enough vertices! (<3)"); return false; } ccPointCloud* cloud = static_cast<ccPointCloud*>(m_associatedCloud); //we instantiate a temporary structure to store each vertex normal (uncompressed) NormsTableType* theNorms = new NormsTableType; if (!theNorms->reserve(vertCount)) { theNorms->release(); return false; } theNorms->fill(0); //allocate compressed normals array on vertices cloud bool normalsWereAllocated = cloud->hasNormals(); if (!normalsWereAllocated && !cloud->resizeTheNormsTable()) { theNorms->release(); return false; } //for each triangle placeIteratorAtBegining(); { for (unsigned i=0; i<triCount; ++i) { CCLib::TriangleSummitsIndexes* tsi = getNextTriangleIndexes(); assert(tsi->i1<vertCount && tsi->i2<vertCount && tsi->i3<vertCount); const CCVector3 *A = cloud->getPoint(tsi->i1); const CCVector3 *B = cloud->getPoint(tsi->i2); const CCVector3 *C = cloud->getPoint(tsi->i3); //compute face normal (right hand rule) CCVector3 N = (*B-*A).cross(*C-*A); //N.normalize(); //DGM: no normalization = weighting by surface! //we add this normal to all triangle vertices PointCoordinateType* N1 = theNorms->getValue(tsi->i1); CCVector3::vadd(N1,N.u,N1); PointCoordinateType* N2 = theNorms->getValue(tsi->i2); CCVector3::vadd(N2,N.u,N2); PointCoordinateType* N3 = theNorms->getValue(tsi->i3); CCVector3::vadd(N3,N.u,N3); } } //for each vertex { for (unsigned i=0; i<vertCount; i++) { PointCoordinateType* N = theNorms->getValue(i); CCVector3::vnormalize(N); cloud->setPointNormal(i,N); theNorms->forwardIterator(); } } showNormals(true); if (!normalsWereAllocated) cloud->showNormals(true); //theNorms->clear(); theNorms->release(); theNorms=0; return true; }
CC_FILE_ERROR DepthMapFileFilter::saveToFile(QString filename, ccGBLSensor* sensor) { assert(sensor); if (!sensor) { return CC_FERR_BAD_ARGUMENT; } //the depth map associated to this sensor const ccGBLSensor::DepthBuffer& db = sensor->getDepthBuffer(); if (db.zBuff.empty()) { ccLog::Warning(QString("[DepthMap] sensor '%1' has no associated depth map (you must compute it first)").arg(sensor->getName())); return CC_FERR_NO_SAVE; //this is not a severe error (the process can go on) } ccGenericPointCloud* cloud = ccHObjectCaster::ToGenericPointCloud(sensor->getParent()); if (!cloud) { ccLog::Warning(QString("[DepthMap] sensor '%1' is not associated to a point cloud!").arg(sensor->getName())); //this is not a severe error (the process can go on) } //opening file FILE* fp = fopen(qPrintable(filename),"wt"); if (!fp) { ccLog::Error(QString("[DepthMap] Can't open file '%1' for writing!").arg(filename)); return CC_FERR_WRITING; } fprintf(fp,"// SENSOR DEPTH MAP\n"); fprintf(fp,"// Associated cloud: %s\n",qPrintable(cloud ? cloud->getName() : "none")); fprintf(fp,"// Pitch = %f [ %f : %f ]\n", sensor->getPitchStep(), sensor->getMinPitch(), sensor->getMaxPitch()); fprintf(fp,"// Yaw = %f [ %f : %f ]\n", sensor->getYawStep(), sensor->getMinYaw(), sensor->getMaxYaw()); fprintf(fp,"// Range = %f\n",sensor->getSensorRange()); fprintf(fp,"// L = %i\n",db.width); fprintf(fp,"// H = %i\n",db.height); fprintf(fp,"/////////////////////////\n"); //an array of projected normals (same size a depth map) ccGBLSensor::NormalGrid* theNorms = NULL; //an array of projected colors (same size a depth map) ccGBLSensor::ColorGrid* theColors = NULL; //if the sensor is associated to a "ccPointCloud", we may also extract //normals and color! if (cloud && cloud->isA(CC_TYPES::POINT_CLOUD)) { ccPointCloud* pc = static_cast<ccPointCloud*>(cloud); unsigned nbPoints = cloud->size(); if (nbPoints == 0) { ccLog::Warning(QString("[DepthMap] sensor '%1' is associated to an empty cloud?!").arg(sensor->getName())); //this is not a severe error (the process can go on) } else { //if possible, we create the array of projected normals if (pc->hasNormals()) { NormsTableType* decodedNorms = new NormsTableType; if (decodedNorms->reserve(nbPoints)) { for (unsigned i=0; i<nbPoints; ++i) decodedNorms->addElement(pc->getPointNormal(i).u); theNorms = sensor->projectNormals(pc,*decodedNorms); decodedNorms->clear(); } else { ccLog::Warning(QString("[DepthMap] not enough memory to load normals on sensor '%1'!").arg(sensor->getName())); } decodedNorms->release(); decodedNorms = 0; } //if possible, we create the array of projected colors if (pc->hasColors()) { GenericChunkedArray<3,ColorCompType>* rgbColors = new GenericChunkedArray<3,ColorCompType>(); rgbColors->reserve(nbPoints); for (unsigned i=0; i<nbPoints; ++i) { //conversion from ColorCompType[3] to unsigned char[3] const ColorCompType* col = pc->getPointColor(i); rgbColors->addElement(col); } theColors = sensor->projectColors(pc,*rgbColors); rgbColors->clear(); rgbColors->release(); rgbColors = 0; } } } const ScalarType* _zBuff = &(db.zBuff.front()); if (theNorms) theNorms->placeIteratorAtBegining(); if (theColors) theColors->placeIteratorAtBegining(); for (unsigned k=0; k<db.height; ++k) { for (unsigned j=0; j<db.width; ++j, ++_zBuff) { //grid index and depth fprintf(fp,"%u %u %.12f",j,k,*_zBuff); //color if (theColors) { const ColorCompType* C = theColors->getCurrentValue(); fprintf(fp," %i %i %i",C[0],C[1],C[2]); theColors->forwardIterator(); } //normal if (theNorms) { const PointCoordinateType* N = theNorms->getCurrentValue(); fprintf(fp," %f %f %f",N[0],N[1],N[2]); theNorms->forwardIterator(); } fprintf(fp,"\n"); } } fclose(fp); fp = 0; if (theNorms) { theNorms->release(); theNorms = 0; } if (theColors) { theColors->release(); theColors = 0; } return CC_FERR_NO_ERROR; }
CC_FILE_ERROR DepthMapFileFilter::saveToOpenedFile(FILE* fp, ccGBLSensor* sensor) { assert(fp && sensor); if (!sensor->getParent()->isKindOf(CC_TYPES::POINT_CLOUD)) { ccLog::Warning(QString("[DepthMap] sensor '%1' is not associated to a point cloud!").arg(sensor->getName())); return CC_FERR_NO_ERROR; //this is not a severe error (the process can go on) } ccGenericPointCloud* cloud = ccHObjectCaster::ToGenericPointCloud(sensor->getParent()); //the depth map associated to this sensor const ccGBLSensor::DepthBuffer& db = sensor->getDepthBuffer(); fprintf(fp,"// CLOUDCOMPARE DEPTH MAP\n"); fprintf(fp,"// Associated cloud: %s\n",qPrintable(cloud->getName())); fprintf(fp,"// dPhi = %f [ %f : %f ]\n", sensor->getDeltaPhi(), sensor->getPhiMin(), sensor->getPhiMax()); fprintf(fp,"// dTheta = %f [ %f : %f ]\n", sensor->getDeltaTheta(), sensor->getThetaMin(), sensor->getThetaMax()); fprintf(fp,"// pMax = %f\n",sensor->getSensorRange()); fprintf(fp,"// L = %i\n",db.width); fprintf(fp,"// H = %i\n",db.height); fprintf(fp,"/////////////////////////\n"); //an array of projected normals (same size a depth map) PointCoordinateType* theNorms = NULL; //an array of projected colors (same size a depth map) colorType* theColors = NULL; //if the sensor is associated to a "ccPointCloud", we may also extract //normals and color! if (cloud->isA(CC_TYPES::POINT_CLOUD)) { ccPointCloud* pc = static_cast<ccPointCloud*>(cloud); unsigned nbPoints = cloud->size(); if (nbPoints == 0) { ccLog::Warning(QString("[DepthMap] sensor '%1' is associated to an empty cloud!").arg(sensor->getName())); return CC_FERR_NO_ERROR; //this is not a severe error (the process can go on) } else { //if possible, we create the array of projected normals if (pc->hasNormals()) { NormsTableType* decodedNorms = new NormsTableType; if (decodedNorms->reserve(nbPoints)) { for (unsigned i=0; i<nbPoints; ++i) decodedNorms->addElement(pc->getPointNormal(i).u); theNorms = sensor->projectNormals(pc,*decodedNorms); decodedNorms->clear(); } else { ccLog::Warning(QString("[DepthMap] not enough memory to load normals on sensor '%1'!").arg(sensor->getName())); } decodedNorms->release(); decodedNorms = 0; } //if possible, we create the array of projected colors if (pc->hasColors()) { GenericChunkedArray<3,colorType>* rgbColors = new GenericChunkedArray<3,colorType>(); rgbColors->reserve(nbPoints); for (unsigned i=0; i<nbPoints; ++i) { //conversion from colorType[3] to unsigned char[3] const colorType* col = pc->getPointColor(i); rgbColors->addElement(col); } theColors = sensor->projectColors(pc,*rgbColors); rgbColors->clear(); rgbColors->release(); rgbColors = 0; } } } PointCoordinateType* _theNorms = theNorms; colorType* _theColors = theColors; ScalarType* _zBuff = db.zBuff; for (unsigned k=0; k<db.height; ++k) { for (unsigned j=0; j<db.width; ++j) { //grid index and depth fprintf(fp,"%i %i %.12f",j,k,*_zBuff++); //color if (_theColors) { fprintf(fp," %i %i %i",_theColors[0],_theColors[1],_theColors[2]); _theColors += 3; } //normal if (_theNorms) { fprintf(fp," %f %f %f",_theNorms[0],_theNorms[1],_theNorms[2]); _theNorms += 3; } fprintf(fp,"\n"); } } if (theNorms) delete[] theNorms; if (theColors) delete[] theColors; return CC_FERR_NO_ERROR; }