int BaseFilter::start() { if (s_computing) { throwError(-32); return -1; } QProgressDialog progressCb("Operation in progress",QString(),0,0); if (m_show_progress) { progressCb.setWindowTitle(getFilterName()); progressCb.show(); QApplication::processEvents(); } s_computeStatus = -1; s_filter = this; s_computing = true; int progress = 0; QFuture<void> future = QtConcurrent::run(doCompute); while (!future.isFinished()) { #if defined(CC_WINDOWS) ::Sleep(500); #else usleep(500 * 1000); #endif if (m_show_progress) progressCb.setValue(++progress); } int is_ok = s_computeStatus; s_filter = 0; s_computing = false; if (m_show_progress) { progressCb.close(); QApplication::processEvents(); } if (is_ok < 0) { throwError(is_ok); return -1; } return 1; }
void OdinPatcher::Impl::updateProgress(uint64_t bytes, uint64_t maxBytes) { if (progressCb) { bool shouldCall = true; if (maxBytes > 0) { // Rate limit... call back only if percentage exceeds 0.01% double oldRatio = (double) oldBytes / maxBytes; double newRatio = (double) bytes / maxBytes; if (newRatio - oldRatio < 0.0001) { shouldCall = false; } } if (shouldCall) { progressCb(bytes, maxBytes, userData); oldBytes = bytes; } } }
void MultiBootPatcher::Impl::updateProgress(uint64_t bytes, uint64_t maxBytes) { if (progressCb) { progressCb(bytes, maxBytes, userData); } }
void qHPR::doAction() { assert(m_app); if (!m_app) return; const ccHObject::Container& selectedEntities = m_app->getSelectedEntities(); size_t selNum = selectedEntities.size(); if ( selNum != 1 || !selectedEntities.front()->isA(CC_TYPES::POINT_CLOUD)) { m_app->dispToConsole("Select only one cloud!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } ccPointCloud* cloud = static_cast<ccPointCloud*>(selectedEntities[0]); ccGLWindow* win = m_app->getActiveGLWindow(); if (!win) { m_app->dispToConsole("No active window!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } //display parameters const ccViewportParameters& params = win->getViewportParameters(); if (!params.perspectiveView) { m_app->dispToConsole("Perspective mode only!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } ccHprDlg dlg(m_app->getMainWindow()); if (!dlg.exec()) return; //progress dialog ccProgressDialog progressCb(false,m_app->getMainWindow()); //unique parameter: the octree subdivision level int octreeLevel = dlg.octreeLevelSpinBox->value(); assert(octreeLevel >= 0 && octreeLevel <= CCLib::DgmOctree::MAX_OCTREE_LEVEL); //compute octree if cloud hasn't any ccOctree::Shared theOctree = cloud->getOctree(); if (!theOctree) { theOctree = cloud->computeOctree(&progressCb); if (theOctree && cloud->getParent()) { m_app->addToDB(cloud->getOctreeProxy()); } } if (!theOctree) { m_app->dispToConsole("Couldn't compute octree!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } CCVector3d viewPoint = params.cameraCenter; if (params.objectCenteredView) { CCVector3d PC = params.cameraCenter - params.pivotPoint; params.viewMat.inverse().apply(PC); viewPoint = params.pivotPoint + PC; } //HPR CCLib::ReferenceCloud* visibleCells = 0; { QElapsedTimer eTimer; eTimer.start(); CCLib::ReferenceCloud* theCellCenters = CCLib::CloudSamplingTools::subsampleCloudWithOctreeAtLevel( cloud, static_cast<unsigned char>(octreeLevel), CCLib::CloudSamplingTools::NEAREST_POINT_TO_CELL_CENTER, &progressCb, theOctree.data()); if (!theCellCenters) { m_app->dispToConsole("Error while simplifying point cloud with octree!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } visibleCells = removeHiddenPoints(theCellCenters,viewPoint,3.5); m_app->dispToConsole(QString("[HPR] Cells: %1 - Time: %2 s").arg(theCellCenters->size()).arg(eTimer.elapsed()/1.0e3)); //warning: after this, visibleCells can't be used anymore as a //normal cloud (as it's 'associated cloud' has been deleted). //Only its indexes are valid! (they are corresponding to octree cells) delete theCellCenters; theCellCenters = 0; } if (visibleCells) { //DGM: we generate a new cloud now, instead of playing with the points visiblity! (too confusing for the user) /*if (!cloud->isVisibilityTableInstantiated() && !cloud->resetVisibilityArray()) { m_app->dispToConsole("Visibility array allocation failed! (Not enough memory?)",ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } ccPointCloud::VisibilityTableType* pointsVisibility = cloud->getTheVisibilityArray(); assert(pointsVisibility); pointsVisibility->fill(POINT_HIDDEN); //*/ CCLib::ReferenceCloud visiblePoints(theOctree->associatedCloud()); unsigned visiblePointCount = 0; unsigned visibleCellsCount = visibleCells->size(); CCLib::DgmOctree::cellIndexesContainer cellIndexes; if (!theOctree->getCellIndexes(static_cast<unsigned char>(octreeLevel), cellIndexes)) { m_app->dispToConsole("Couldn't fetch the list of octree cell indexes! (Not enough memory?)",ccMainAppInterface::ERR_CONSOLE_MESSAGE); delete visibleCells; return; } for (unsigned i=0; i<visibleCellsCount; ++i) { //cell index unsigned index = visibleCells->getPointGlobalIndex(i); //points in this cell... CCLib::ReferenceCloud Yk(theOctree->associatedCloud()); theOctree->getPointsInCellByCellIndex(&Yk,cellIndexes[index],static_cast<unsigned char>(octreeLevel)); //...are all visible /*unsigned count = Yk.size(); for (unsigned j=0;j<count;++j) pointsVisibility->setValue(Yk.getPointGlobalIndex(j),POINT_VISIBLE); visiblePointCount += count; //*/ if (!visiblePoints.add(Yk)) { m_app->dispToConsole("Not enough memory!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); delete visibleCells; return; } } delete visibleCells; visibleCells = 0; m_app->dispToConsole(QString("[HPR] Visible points: %1").arg(visiblePointCount)); if (visiblePoints.size() == cloud->size()) { m_app->dispToConsole("No points were removed!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); } else { //create cloud from visibility selection ccPointCloud* newCloud = cloud->partialClone(&visiblePoints); if (newCloud) { newCloud->setDisplay(newCloud->getDisplay()); newCloud->setVisible(true); newCloud->setName(cloud->getName()+QString(".visible_points")); cloud->setEnabled(false); //add associated viewport object cc2DViewportObject* viewportObject = new cc2DViewportObject(QString("Viewport")); viewportObject->setParameters(params); newCloud->addChild(viewportObject); m_app->addToDB(newCloud); newCloud->redrawDisplay(); } else { m_app->dispToConsole("Not enough memory!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); } } } //currently selected entities appearance may have changed! m_app->refreshAll(); }
void qRansacSD::doAction() { assert(m_app); if (!m_app) return; const ccHObject::Container& selectedEntities = m_app->getSelectedEntities(); size_t selNum = selectedEntities.size(); if (selNum!=1) { m_app->dispToConsole("Select only one cloud!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } ccHObject* ent = selectedEntities[0]; assert(ent); if (!ent || !ent->isA(CC_POINT_CLOUD)) { m_app->dispToConsole("Select a real point cloud!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } ccPointCloud* pc = static_cast<ccPointCloud*>(ent); //input cloud size_t count = (size_t)pc->size(); bool hasNorms = pc->hasNormals(); PointCoordinateType bbMin[3],bbMax[3]; pc->getBoundingBox(bbMin,bbMax); //Convert CC point cloud to RANSAC_SD type PointCloud cloud; { try { cloud.reserve(count); } catch(...) { m_app->dispToConsole("Not enough memory!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } //default point & normal Point Pt; Pt.normal[0] = 0.0; Pt.normal[1] = 0.0; Pt.normal[2] = 0.0; for (unsigned i=0; i<(unsigned)count; ++i) { const CCVector3* P = pc->getPoint(i); Pt.pos[0] = P->x; Pt.pos[1] = P->y; Pt.pos[2] = P->z; if (hasNorms) { const PointCoordinateType* N = pc->getPointNormal(i); Pt.normal[0] = N[0]; Pt.normal[1] = N[1]; Pt.normal[2] = N[2]; } cloud.push_back(Pt); } //manually set bounding box! Vec3f cbbMin,cbbMax; cbbMin[0] = bbMin[0]; cbbMin[1] = bbMin[1]; cbbMin[2] = bbMin[2]; cbbMax[0] = bbMax[0]; cbbMax[1] = bbMax[1]; cbbMax[2] = bbMax[2]; cloud.setBBox(cbbMin,cbbMax); } //cloud scale (useful for setting several parameters const float scale = cloud.getScale(); //init dialog with default values ccRansacSDDlg rsdDlg(m_app->getMainWindow()); rsdDlg.epsilonDoubleSpinBox->setValue(.01f * scale); // set distance threshold to .01f of bounding box width // NOTE: Internally the distance threshold is taken as 3 * ransacOptions.m_epsilon!!! rsdDlg.bitmapEpsilonDoubleSpinBox->setValue(.02f * scale); // set bitmap resolution to .02f of bounding box width // NOTE: This threshold is NOT multiplied internally! rsdDlg.supportPointsSpinBox->setValue(s_supportPoints); rsdDlg.normThreshDoubleSpinBox->setValue(s_normThresh); rsdDlg.probaDoubleSpinBox->setValue(s_proba); rsdDlg.planeCheckBox->setChecked(s_primEnabled[0]); rsdDlg.sphereCheckBox->setChecked(s_primEnabled[1]); rsdDlg.cylinderCheckBox->setChecked(s_primEnabled[2]); rsdDlg.coneCheckBox->setChecked(s_primEnabled[3]); rsdDlg.torusCheckBox->setChecked(s_primEnabled[4]); if (!rsdDlg.exec()) return; //for parameters persistence { s_supportPoints = rsdDlg.supportPointsSpinBox->value(); s_normThresh = rsdDlg.normThreshDoubleSpinBox->value(); s_proba = rsdDlg.probaDoubleSpinBox->value(); //consistency check { unsigned char primCount = 0; for (unsigned char k=0; k<5; ++k) primCount += (unsigned)s_primEnabled[k]; if (primCount==0) { m_app->dispToConsole("No primitive type selected!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } } s_primEnabled[0] = rsdDlg.planeCheckBox->isChecked(); s_primEnabled[1] = rsdDlg.sphereCheckBox->isChecked(); s_primEnabled[2] = rsdDlg.cylinderCheckBox->isChecked(); s_primEnabled[3] = rsdDlg.coneCheckBox->isChecked(); s_primEnabled[4] = rsdDlg.torusCheckBox->isChecked(); } //import parameters from dialog RansacShapeDetector::Options ransacOptions; { ransacOptions.m_epsilon = rsdDlg.epsilonDoubleSpinBox->value(); ransacOptions.m_bitmapEpsilon = rsdDlg.bitmapEpsilonDoubleSpinBox->value(); ransacOptions.m_normalThresh = rsdDlg.normThreshDoubleSpinBox->value(); ransacOptions.m_minSupport = rsdDlg.supportPointsSpinBox->value(); ransacOptions.m_probability = rsdDlg.probaDoubleSpinBox->value(); } //progress dialog ccProgressDialog progressCb(false,m_app->getMainWindow()); progressCb.setRange(0,0); if (!hasNorms) { progressCb.setInfo("Computing normals (please wait)"); progressCb.start(); QApplication::processEvents(); cloud.calcNormals(.01f * scale); if (pc->reserveTheNormsTable()) { for (size_t i=0; i<count; ++i) { CCVector3 N(cloud[i].normal); N.normalize(); pc->addNorm(N.u); } pc->showNormals(true); //currently selected entities appearance may have changed! pc->prepareDisplayForRefresh_recursive(); } else { m_app->dispToConsole("Not enough memory to compute normals!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } } // set which primitives are to be detected by adding the respective constructors RansacShapeDetector detector(ransacOptions); // the detector object if (rsdDlg.planeCheckBox->isChecked()) detector.Add(new PlanePrimitiveShapeConstructor()); if (rsdDlg.sphereCheckBox->isChecked()) detector.Add(new SpherePrimitiveShapeConstructor()); if (rsdDlg.cylinderCheckBox->isChecked()) detector.Add(new CylinderPrimitiveShapeConstructor()); if (rsdDlg.coneCheckBox->isChecked()) detector.Add(new ConePrimitiveShapeConstructor()); if (rsdDlg.torusCheckBox->isChecked()) detector.Add(new TorusPrimitiveShapeConstructor()); size_t remaining = count; typedef std::pair< MiscLib::RefCountPtr< PrimitiveShape >, size_t > DetectedShape; MiscLib::Vector< DetectedShape > shapes; // stores the detected shapes // run detection // returns number of unassigned points // the array shapes is filled with pointers to the detected shapes // the second element per shapes gives the number of points assigned to that primitive (the support) // the points belonging to the first shape (shapes[0]) have been sorted to the end of pc, // i.e. into the range [ pc.size() - shapes[0].second, pc.size() ) // the points of shape i are found in the range // [ pc.size() - \sum_{j=0..i} shapes[j].second, pc.size() - \sum_{j=0..i-1} shapes[j].second ) { progressCb.setInfo("Operation in progress"); progressCb.setMethodTitle("Ransac Shape Detection"); progressCb.start(); //run in a separate thread s_detector = &detector; s_shapes = &shapes; s_cloud = &cloud; QFuture<void> future = QtConcurrent::run(doDetection); unsigned progress = 0; while (!future.isFinished()) { #if defined(_WIN32) || defined(WIN32) ::Sleep(500); #else sleep(500); #endif progressCb.update(++progress); //Qtconcurrent::run can't be canceled! /*if (progressCb.isCancelRequested()) { future.cancel(); future.waitForFinished(); s_remainingPoints = count; break; } //*/ } remaining = s_remainingPoints; progressCb.stop(); QApplication::processEvents(); } //else //{ // remaining = detector.Detect(cloud, 0, cloud.size(), &shapes); //} #ifdef _DEBUG FILE* fp = fopen("RANS_SD_trace.txt","wt"); fprintf(fp,"[Options]\n"); fprintf(fp,"epsilon=%f\n",ransacOptions.m_epsilon); fprintf(fp,"bitmap epsilon=%f\n",ransacOptions.m_bitmapEpsilon); fprintf(fp,"normal thresh=%f\n",ransacOptions.m_normalThresh); fprintf(fp,"min support=%i\n",ransacOptions.m_minSupport); fprintf(fp,"probability=%f\n",ransacOptions.m_probability); fprintf(fp,"\n[Statistics]\n"); fprintf(fp,"input points=%i\n",count); fprintf(fp,"segmented=%i\n",count-remaining); fprintf(fp,"remaining=%i\n",remaining); if (shapes.size()>0) { fprintf(fp,"\n[Shapes]\n"); for (unsigned i=0; i<shapes.size(); ++i) { PrimitiveShape* shape = shapes[i].first; unsigned shapePointsCount = shapes[i].second; std::string desc; shape->Description(&desc); fprintf(fp,"#%i - %s - %i points\n",i+1,desc.c_str(),shapePointsCount); } } fclose(fp); #endif if (remaining == count) { m_app->dispToConsole("Segmentation failed...",ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } if (shapes.size() > 0) { ccHObject* group = 0; for (MiscLib::Vector<DetectedShape>::const_iterator it = shapes.begin(); it != shapes.end(); ++it) { const PrimitiveShape* shape = it->first; size_t shapePointsCount = it->second; //too many points?! if (shapePointsCount > count) { m_app->dispToConsole("Inconsistent result!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); break; } std::string desc; shape->Description(&desc); //new cloud for sub-part ccPointCloud* pcShape = new ccPointCloud(desc.c_str()); //we fill cloud with sub-part points if (!pcShape->reserve((unsigned)shapePointsCount)) { m_app->dispToConsole("Not enough memory!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); delete pcShape; break; } bool saveNormals = pcShape->reserveTheNormsTable(); for (size_t j=0; j<shapePointsCount; ++j) { pcShape->addPoint(CCVector3(cloud[count-1-j].pos)); if (saveNormals) pcShape->addNorm(cloud[count-1-j].normal); } //random color unsigned char col[3]= { (unsigned char)(255.0*(float)rand()/(float)RAND_MAX), (unsigned char)(255.0*(float)rand()/(float)RAND_MAX), 0 }; col[2]=255-(col[1]+col[2])/2; pcShape->setRGBColor(col); pcShape->showColors(true); pcShape->showNormals(saveNormals); pcShape->setVisible(true); //convert detected primitive into a CC primitive type ccGenericPrimitive* prim = 0; switch(shape->Identifier()) { case 0: //plane { const PlanePrimitiveShape* plane = static_cast<const PlanePrimitiveShape*>(shape); Vec3f G = plane->Internal().getPosition(); Vec3f N = plane->Internal().getNormal(); Vec3f X = plane->getXDim(); Vec3f Y = plane->getYDim(); //we look for real plane extents float minX,maxX,minY,maxY; for (size_t j=0; j<shapePointsCount; ++j) { std::pair<float,float> param; plane->Parameters(cloud[count-1-j].pos,¶m); if (j!=0) { if (minX<param.first) minX=param.first; else if (maxX>param.first) maxX=param.first; if (minY<param.second) minY=param.second; else if (maxY>param.second) maxY=param.second; } else { minX=maxX=param.first; minY=maxY=param.second; } } //we recenter plane (as it is not always the case!) float dX = maxX-minX; float dY = maxY-minY; G += X * (minX+dX*0.5); G += Y * (minY+dY*0.5); //we build matrix from these vecctors ccGLMatrix glMat(CCVector3(X.getValue()), CCVector3(Y.getValue()), CCVector3(N.getValue()), CCVector3(G.getValue())); //plane primitive prim = new ccPlane(dX,dY,&glMat); } break; case 1: //sphere { const SpherePrimitiveShape* sphere = static_cast<const SpherePrimitiveShape*>(shape); float radius = sphere->Internal().Radius(); Vec3f CC = sphere->Internal().Center(); pcShape->setName(QString("Sphere (r=%1)").arg(radius,0,'f')); //we build matrix from these vecctors ccGLMatrix glMat; glMat.setTranslation(CCVector3(CC.getValue())); //sphere primitive prim = new ccSphere(radius,&glMat); prim->setEnabled(false); } break; case 2: //cylinder { const CylinderPrimitiveShape* cyl = static_cast<const CylinderPrimitiveShape*>(shape); Vec3f G = cyl->Internal().AxisPosition(); Vec3f N = cyl->Internal().AxisDirection(); Vec3f X = cyl->Internal().AngularDirection(); Vec3f Y = N.cross(X); float r = cyl->Internal().Radius(); float hMin = cyl->MinHeight(); float hMax = cyl->MaxHeight(); float h = hMax-hMin; G += N * (hMin+h*0.5); pcShape->setName(QString("Cylinder (r=%1/h=%2)").arg(r,0,'f').arg(h,0,'f')); //we build matrix from these vecctors ccGLMatrix glMat(CCVector3(X.getValue()), CCVector3(Y.getValue()), CCVector3(N.getValue()), CCVector3(G.getValue())); //cylinder primitive prim = new ccCylinder(r,h,&glMat); prim->setEnabled(false); } break; case 3: //cone { const ConePrimitiveShape* cone = static_cast<const ConePrimitiveShape*>(shape); Vec3f CC = cone->Internal().Center(); Vec3f CA = cone->Internal().AxisDirection(); float alpha = cone->Internal().Angle(); //compute max height CCVector3 maxP(CC.getValue()); float maxHeight = 0; for (size_t j=0; j<shapePointsCount; ++j) { float h = cone->Internal().Height(cloud[count-1-j].pos); if (h>maxHeight) { maxHeight=h; maxP = CCVector3(cloud[count-1-j].pos); } } pcShape->setName(QString("Cone (alpha=%1/h=%2)").arg(alpha,0,'f').arg(maxHeight,0,'f')); float radius = tan(alpha)*maxHeight; CCVector3 Z = CCVector3(CA.getValue()); CCVector3 C = CCVector3(CC.getValue()); //cone apex //construct remaining of base Z.normalize(); CCVector3 X = maxP - (C + maxHeight * Z); X.normalize(); CCVector3 Y = Z * X; //we build matrix from these vecctors ccGLMatrix glMat(X,Y,Z,C+(maxHeight*0.5)*Z); //cone primitive prim = new ccCone(0,radius,maxHeight,0,0,&glMat); prim->setEnabled(false); } break; case 4: //torus { const TorusPrimitiveShape* torus = static_cast<const TorusPrimitiveShape*>(shape); if (torus->Internal().IsAppleShaped()) { m_app->dispToConsole("[qRansacSD] Apple-shaped torus are not handled by CloudCompare!",ccMainAppInterface::WRN_CONSOLE_MESSAGE); } else { Vec3f CC = torus->Internal().Center(); Vec3f CA = torus->Internal().AxisDirection(); float minRadius = torus->Internal().MinorRadius(); float maxRadius = torus->Internal().MajorRadius(); pcShape->setName(QString("Torus (r=%1/R=%2)").arg(minRadius,0,'f').arg(maxRadius,0,'f')); CCVector3 Z = CCVector3(CA.getValue()); CCVector3 C = CCVector3(CC.getValue()); //construct remaining of base CCVector3 X = Z.orthogonal(); CCVector3 Y = Z * X; //we build matrix from these vecctors ccGLMatrix glMat(X,Y,Z,C); //torus primitive prim = new ccTorus(maxRadius-minRadius,maxRadius+minRadius,M_PI*2.0,false,0,&glMat); prim->setEnabled(false); } } break; } //is there a primitive to add to part cloud? if (prim) { prim->applyGLTransformation_recursive(); pcShape->addChild(prim); prim->setDisplay(pcShape->getDisplay()); prim->setColor(col); prim->showColors(true); prim->setVisible(true); } if (!group) { group = new ccHObject(QString("Ransac Detected Shapes (%1)").arg(ent->getName())); m_app->addToDB(group,true,0,false); } group->addChild(pcShape); m_app->addToDB(pcShape,true,0,false); count -= shapePointsCount; QApplication::processEvents(); } if (group) { assert(group->getChildrenNumber()!=0); //we hide input cloud pc->setEnabled(false); m_app->dispToConsole("[qRansacSD] Input cloud has been automtically hidden!",ccMainAppInterface::WRN_CONSOLE_MESSAGE); //we add new group to DB/display group->setVisible(true); group->setDisplay_recursive(pc->getDisplay()); group->prepareDisplayForRefresh_recursive(); m_app->refreshAll(); } } }
void qPCV::doAction() { assert(m_app); if (!m_app) return; const ccHObject::Container& selectedEntities = m_app->getSelectedEntities(); unsigned selNum = selectedEntities.size(); if (selNum!=1) { m_app->dispToConsole("Select only one cloud or one mesh!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } ccHObject* ent = selectedEntities[0]; ccGenericPointCloud* cloud = NULL; ccGenericMesh* mesh = NULL; if (ent->isKindOf(CC_POINT_CLOUD)) { cloud = static_cast<ccGenericPointCloud*>(ent); } else if (ent->isKindOf(CC_MESH)) { mesh = static_cast<ccGenericMesh*>(ent); cloud = mesh->getAssociatedCloud(); } else { m_app->dispToConsole("Select a point cloud or a mesh!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } if (!cloud->isA(CC_POINT_CLOUD)) //TODO { m_app->dispToConsole("Select a real point cloud (or a mesh associated to a real point cloud)!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } ccPointCloud* pc = static_cast<ccPointCloud*>(cloud); ccPcvDlg dlg(m_app->getMainWindow()); //for meshes only if (!mesh) dlg.closedMeshCheckBox->setEnabled(false); //for using clouds normals as rays std::vector<ccGenericPointCloud*> cloudsWithNormals; if (m_app->dbRoot()) { ccHObject* root = m_app->dbRoot(); if (root) { ccHObject::Container clouds; root->filterChildren(clouds,true,CC_POINT_CLOUD); for (unsigned i=0;i<clouds.size();++i) { //we keep only clouds with normals ccGenericPointCloud* cloud = static_cast<ccGenericPointCloud*>(clouds[i]); if (cloud && cloud->hasNormals()) { cloudsWithNormals.push_back(cloud); QString cloudTitle = QString("%1 - %2 points").arg(cloud->getName()).arg(cloud->size()); if (cloud->getParent() && cloud->getParent()->isKindOf(CC_MESH)) cloudTitle.append(QString(" (%1)").arg(cloud->getParent()->getName())); dlg.cloudsComboBox->addItem(cloudTitle); } } } } if (cloudsWithNormals.empty()) dlg.useCloudRadioButton->setEnabled(false); if (!dlg.exec()) return; //on récupère le champ PCV s'il existe déjà, et on le créé sinon int sfIdx = pc->getScalarFieldIndexByName(CC_PCV_FIELD_LABEL_NAME); if (sfIdx<0) sfIdx=pc->addScalarField(CC_PCV_FIELD_LABEL_NAME,true); if (sfIdx<0) { m_app->dispToConsole("Couldn't allocate a new scalar field for computing PCV field ! Try to free some memory ...",ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } pc->setCurrentScalarField(sfIdx); unsigned raysNumber = dlg.raysSpinBox->value(); unsigned res = dlg.resSpinBox->value(); bool meshIsClosed = (mesh ? dlg.closedMeshCheckBox->checkState()==Qt::Checked : false); bool mode360 = !dlg.mode180CheckBox->isChecked(); //progress dialog ccProgressDialog progressCb(true,m_app->getMainWindow()); //PCV type ShadeVis bool success = false; if (!cloudsWithNormals.empty() && dlg.useCloudRadioButton->isChecked()) { //Version with cloud normals as light rays assert(dlg.cloudsComboBox->currentIndex() < (int)cloudsWithNormals.size()); ccGenericPointCloud* pc = cloudsWithNormals[dlg.cloudsComboBox->currentIndex()]; std::vector<CCVector3> rays; unsigned count = pc->size(); rays.resize(count); for (unsigned i=0;i<count;++i) rays[i]=CCVector3(pc->getPointNormal(i)); success = PCV::Launch(rays,cloud,mesh,meshIsClosed,res,res,&progressCb); } else { //Version with rays sampled on a sphere success = (PCV::Launch(raysNumber,cloud,mesh,meshIsClosed,mode360,res,res,&progressCb)>0); } if (!success) { pc->deleteScalarField(sfIdx); m_app->dispToConsole("En error occured during the PCV field computation!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } else { pc->getCurrentInScalarField()->computeMinAndMax(); pc->setCurrentDisplayedScalarField(sfIdx); ccScalarField* sf = static_cast<ccScalarField*>(pc->getScalarField(sfIdx)); if (sf) sf->setColorRamp(GREY); ent->showSF(true); ent->showNormals(false); ent->prepareDisplayForRefresh_recursive(); } //currently selected entities parameters may have changed! m_app->updateUI(); //currently selected entities appearance may have changed! m_app->refreshAll(); }