BOOL Ccoin_lookerDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 auto g_CoinList = LoadCoinList(GetAppDir()); if (g_CoinList.size()) { int idx = 0; for (auto it = g_CoinList.begin(); it != g_CoinList.end(); ++it) { shared_ptr<ICoinOption> pCoinOption = *it; shared_ptr<IUserContext> pWork = create_coin_work(pCoinOption); boost::thread th(boost::bind(&IUserContext::load_db, pWork)); shared_ptr<CRecvDialog> pDlg(new CRecvDialog(pWork, &m_tab1)); pDlg->Create(CRecvDialog::IDD); CRect r; pDlg->GetWindowRect(r); r.top += 18; r.left += 14; pDlg->MoveWindow(r); m_tab1.InsertItem(m_tab1.GetItemCount(), pCoinOption->prev_name.c_str()); m_vlist.push_back(pDlg); } m_vlist[0]->ShowWindow(SW_SHOW); } return TRUE; // 除非将焦点设置到控件,否则返回 TRUE }
void DomainListView::changePressed() { QListViewItem *index = domainSpecificLV->currentItem(); if ( index == 0 ) { KMessageBox::information( 0, i18n("You must first select a policy to be changed." ) ); return; } Policies *pol = domainPolicies[index]; // This must be copied because the policy dialog is allowed to change // the data even if the changes are rejected in the end. Policies *pol_copy = copyPolicies(pol); PolicyDialog pDlg( pol_copy, this ); pDlg.setDisableEdit( true, index->text(0) ); setupPolicyDlg(ChangeButton,pDlg,pol_copy); if( pDlg.exec() ) { pol_copy->setDomain(pDlg.domain()); domainPolicies[index] = pol_copy; pol_copy = pol; index->setText(0, pDlg.domain() ); index->setText(1, pDlg.featureEnabledPolicyText()); emit changed(true); } delete pol_copy; }
void ccNormalComputationDlg::autoEstimateRadius() { if (!m_cloud) { assert(false); return; } if (!m_cloud->getOctree()) { ccProgressDialog pDlg(true, this); if (!m_cloud->computeOctree(&pDlg)) { ccLog::Error(QString("Could not compute octree for cloud '%1'").arg(m_cloud->getName())); autoRadiusToolButton->setVisible(false); return; } } PointCoordinateType radius = ccNormalVectors::GuessBestRadius(m_cloud, m_cloud->getOctree().data()); if (radius > 0) { radiusDoubleSpinBox->setValue(radius); } }
CC_FILE_ERROR BinFilter::loadFile(const char* filename, ccHObject& container, bool alwaysDisplayLoadDialog/*=true*/, bool* coordinatesShiftEnabled/*=0*/, double* coordinatesShift/*=0*/) { ccLog::Print("[BIN] Opening file '%s'...",filename); //opening file QFile in(filename); if (!in.open(QIODevice::ReadOnly)) return CC_FERR_READING; uint32_t firstBytes = 0; if (in.read((char*)&firstBytes,4)<0) return CC_FERR_READING; bool v1 = (strncmp((char*)&firstBytes,"CCB2",4) != 0); if (v1) { return LoadFileV1(in,container,static_cast<unsigned>(firstBytes),alwaysDisplayLoadDialog); //firstBytes == number of scans for V1 files! } else { if (alwaysDisplayLoadDialog) { QProgressDialog pDlg(QString("Loading: %1").arg(QFileInfo(filename).fileName()),QString(),0,0/*static_cast<int>(in.size())*/); pDlg.setWindowTitle("BIN file"); pDlg.show(); //concurrent call in a separate thread s_file = ∈ s_container = &container; QFuture<CC_FILE_ERROR> future = QtConcurrent::run(_LoadFileV2); while (!future.isFinished()) { #if defined(CC_WINDOWS) ::Sleep(500); #else usleep(500 * 1000); #endif if (alwaysDisplayLoadDialog) { pDlg.setValue(pDlg.value()+1); //pDlg.setValue(static_cast<int>(in.pos())); //DGM: in fact, the file reading part is just half of the work! QApplication::processEvents(); } } s_file = 0; s_container = 0; return future.result(); } else { return BinFilter::LoadFileV2(in,container); } } }
void CVideoRecvTestDlg::OnBnClickedButton3() { if(*m_hDevice == NULL) { return; } CSetVideoEnahnceFlagDlg pDlg(m_hDevice, this); pDlg.DoModal(); }
void CDialogMediaControl::OnBnClickedButtonMediaFullscreen() { m_bFullScreen = !m_bFullScreen; CRect newWindowSize; CWnd *pDlg(m_pDialogPreviewMedia->GetParent()); if (m_bFullScreen) { // Save current rect pDlg->GetWindowRect(&m_WindowSize); GetDesktopWindow()->GetWindowRect(&newWindowSize); } else { newWindowSize = m_WindowSize; } pDlg->SetWindowPos(&wndTopMost, newWindowSize.left, newWindowSize.top, newWindowSize.right-newWindowSize.left, newWindowSize.bottom-newWindowSize.top, 0); }
void DomainListView::addPressed() { // JavaPolicies pol_copy(m_pConfig,m_groupname,false); Policies *pol = createPolicies(); pol->defaults(); PolicyDialog pDlg(pol, this); setupPolicyDlg(AddButton,pDlg,pol); if( pDlg.exec() ) { QListViewItem* index = new QListViewItem( domainSpecificLV, pDlg.domain(), pDlg.featureEnabledPolicyText() ); pol->setDomain(pDlg.domain()); domainPolicies.insert(index, pol); domainSpecificLV->setCurrentItem( index ); emit changed(true); } else { delete pol; } updateButton(); }
CC_FILE_ERROR BinFilter::saveToFile(ccHObject* root, const char* filename) { if (!root || !filename) return CC_FERR_BAD_ARGUMENT; QFile out(filename); if (!out.open(QIODevice::WriteOnly)) return CC_FERR_WRITING; QProgressDialog pDlg(QString("Please wait... saving in progress"),QString(),0,0); pDlg.setWindowTitle("BIN file"); pDlg.setModal(true); pDlg.show(); //concurrent call s_file = &out; s_container = root; QFuture<CC_FILE_ERROR> future = QtConcurrent::run(_SaveFileV2); while (!future.isFinished()) { #if defined(CC_WINDOWS) ::Sleep(500); #else usleep(500 * 1000); #endif pDlg.setValue(pDlg.value()+1); QApplication::processEvents(); } s_file = 0; s_container = 0; CC_FILE_ERROR result = future.result(); if (result == CC_FERR_NO_ERROR) ccLog::Print("[BIN] File %s saved successfully",filename); return result; }
CC_FILE_ERROR BinFilter::saveToFile(ccHObject* root, QString filename, SaveParameters& parameters) { if (!root || filename.isNull()) return CC_FERR_BAD_ARGUMENT; QFile out(filename); if (!out.open(QIODevice::WriteOnly)) return CC_FERR_WRITING; ccProgressDialog pDlg(false, parameters.parentWidget); pDlg.setMethodTitle(QObject::tr("BIN file")); pDlg.setInfo(QObject::tr("Please wait... saving in progress")); pDlg.setRange(0, 0); pDlg.setModal(true); pDlg.show(); //concurrent call s_file = &out; s_container = root; QFuture<CC_FILE_ERROR> future = QtConcurrent::run(_SaveFileV2); while (!future.isFinished()) { #if defined(CC_WINDOWS) ::Sleep(500); #else usleep(500 * 1000); #endif pDlg.setValue(pDlg.value()+1); QApplication::processEvents(); } s_file = 0; s_container = 0; CC_FILE_ERROR result = future.result(); return result; }
BOOL CMainDlg::TestPrinter(LPTSTR printer) { HANDLE p; PRINTER_INFO_2 *pInfo; DWORD need = 0; if (!::OpenPrinter(printer, &p, NULL)) return FALSE; ::GetPrinter(p, 2, NULL, 0, &need); if (!need) return FALSE; pInfo = (PRINTER_INFO_2 *) new BYTE[need]; ::GetPrinter(p, 2, (LPBYTE) pInfo, need, &need); CPInfoDlg pDlg(pInfo); pDlg.DoModal(); delete pInfo; return TRUE; }
void ccAlignDlg::estimateDelta() { unsigned i, nb; float meanDensity, meanSqrDensity, dev, value; ccProgressDialog pDlg(false,this); CCLib::ReferenceCloud *sampledData = getSampledData(); //we have to work on a copy of the cloud in order to prevent the algorithms from modifying the original cloud. CCLib::ChunkedPointCloud* cloud = new CCLib::ChunkedPointCloud(); cloud->reserve(sampledData->size()); for(i=0; i<sampledData->size(); i++) cloud->addPoint(*sampledData->getPoint(i)); cloud->enableScalarField(); CCLib::GeometricalAnalysisTools::computeLocalDensity(cloud, &pDlg); nb = 0; meanDensity = 0.; meanSqrDensity = 0.; for(i=0; i<cloud->size(); i++) { value = cloud->getPointScalarValue(i); if(value > ZERO_TOLERANCE) { value = 1/value; meanDensity += value; meanSqrDensity += value*value; nb++; } } meanDensity /= (float)nb; meanSqrDensity /= (float)nb; dev = meanSqrDensity-(meanDensity*meanDensity); delta->setValue(meanDensity+dev); delete sampledData; delete cloud; }
CC_FILE_ERROR PNFilter::loadFile(const 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 = 6*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 QScopedPointer<ccProgressDialog> pDlg(0); if (parameters.parentWidget) { pDlg.reset(new ccProgressDialog(true, parameters.parentWidget)); //cancel available pDlg->setMethodTitle(QObject::tr("Open PN file")); pDlg->setInfo(QObject::tr("Points: %L1").arg( numberOfPoints )); pDlg->start(); } CCLib::NormalizedProgress nprogress(pDlg.data(), numberOfPoints); 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) 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->reserveTheNormsTable()) { result = CC_FERR_NOT_ENOUGH_MEMORY; if (loadedCloud) delete loadedCloud; loadedCloud = 0; break; } loadedCloud->showNormals(true); } //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 = CCVector3::fromArray(rBuff); loadedCloud->addPoint(P); } else { result = CC_FERR_READING; break; } //then the 3 components of the normal vector if (in.read((char*)rBuff,3*sizeof(float))>=0) { loadedCloud->addNorm(CCVector3::fromArray(rBuff)); } else { //add fake normal for consistency then break loadedCloud->addNorm(s_defaultNorm); result = CC_FERR_READING; break; } ++pointsRead; if (pDlg && !nprogress.oneStep()) { result = CC_FERR_CANCELED_BY_USER; break; } } in.close(); if (loadedCloud) { loadedCloud->shrinkToFit(); container.addChild(loadedCloud); } return result; }
CC_FILE_ERROR PNFilter::saveToFile(ccHObject* entity, const QString& filename, const SaveParameters& parameters) { if (!entity || filename.isEmpty()) return CC_FERR_BAD_ARGUMENT; //the cloud to save ccGenericPointCloud* theCloud = ccHObjectCaster::ToGenericPointCloud(entity); if (!theCloud) { ccLog::Warning("[PN] This filter can only save one cloud at a time!"); return CC_FERR_BAD_ENTITY_TYPE; } unsigned numberOfPoints = theCloud->size(); if (numberOfPoints == 0) { ccLog::Warning("[PN] Input cloud is empty!"); return CC_FERR_NO_SAVE; } //open binary file for writing QFile out(filename); if (!out.open(QIODevice::WriteOnly)) return CC_FERR_WRITING; //Has the cloud been recentered? if (theCloud->isShifted()) ccLog::Warning(QString("[PNFilter::save] Can't recenter or rescale cloud '%1' when saving it in a PN file!").arg(theCloud->getName())); bool hasNorms = theCloud->hasNormals(); if (!hasNorms) ccLog::Warning(QString("[PNFilter::save] Cloud '%1' has no normal (we will save points with a default normal)!").arg(theCloud->getName())); float norm[3] = { static_cast<float>(s_defaultNorm.x), static_cast<float>(s_defaultNorm.y), static_cast<float>(s_defaultNorm.z) }; //progress dialog QScopedPointer<ccProgressDialog> pDlg(0); if (pDlg) { pDlg.reset(new ccProgressDialog(true, parameters.parentWidget)); //cancel available pDlg->setMethodTitle(QObject::tr("Save PN file")); pDlg->setInfo(QObject::tr("Points: %L1").arg( numberOfPoints )); pDlg->start(); } CCLib::NormalizedProgress nprogress(pDlg.data(), numberOfPoints); CC_FILE_ERROR result = CC_FERR_NO_ERROR; for (unsigned i=0; i<numberOfPoints; i++) { //write point { const CCVector3* P = theCloud->getPoint(i); //conversion to float CCVector3f Pfloat = CCVector3f::fromArray(P->u); if (out.write(reinterpret_cast<const char*>(Pfloat.u),3*sizeof(float)) < 0) { result = CC_FERR_WRITING; break; } } //write normal if (hasNorms) { const CCVector3& N = theCloud->getPointNormal(i); //conversion to float norm[0] = static_cast<float>(N.x); norm[1] = static_cast<float>(N.y); norm[2] = static_cast<float>(N.z); } if (out.write(reinterpret_cast<const char*>(norm),3*sizeof(float)) < 0) { result = CC_FERR_WRITING; break; } if (pDlg && !nprogress.oneStep()) { result = CC_FERR_CANCELED_BY_USER; break; } } out.close(); return result; }
bool ccRegistrationTools::ICP( ccHObject* data, ccHObject* model, ccGLMatrix& transMat, double &finalScale, double& finalRMS, unsigned& finalPointCount, double minRMSDecrease, unsigned maxIterationCount, unsigned randomSamplingLimit, bool removeFarthestPoints, CCLib::ICPRegistrationTools::CONVERGENCE_TYPE method, bool adjustScale, double finalOverlapRatio/*=1.0*/, bool useDataSFAsWeights/*=false*/, bool useModelSFAsWeights/*=false*/, int filters/*=CCLib::ICPRegistrationTools::SKIP_NONE*/, int maxThreadCount/*=0*/, QWidget* parent/*=0*/) { //progress bar ccProgressDialog pDlg(false, parent); Garbage<CCLib::GenericIndexedCloudPersist> cloudGarbage; //if the 'model' entity is a mesh, we need to sample points on it CCLib::GenericIndexedCloudPersist* modelCloud = 0; ccGenericMesh* modelMesh = 0; if (model->isKindOf(CC_TYPES::MESH)) { modelMesh = ccHObjectCaster::ToGenericMesh(model); modelCloud = modelMesh->getAssociatedCloud(); } else { modelCloud = ccHObjectCaster::ToGenericPointCloud(model); } //if the 'data' entity is a mesh, we need to sample points on it CCLib::GenericIndexedCloudPersist* dataCloud = 0; if (data->isKindOf(CC_TYPES::MESH)) { dataCloud = CCLib::MeshSamplingTools::samplePointsOnMesh(ccHObjectCaster::ToGenericMesh(data), s_defaultSampledPointsOnDataMesh, &pDlg); if (!dataCloud) { ccLog::Error("[ICP] Failed to sample points on 'data' mesh!"); return false; } cloudGarbage.add(dataCloud); } else { dataCloud = ccHObjectCaster::ToGenericPointCloud(data); } //we activate a temporary scalar field for registration distances computation CCLib::ScalarField* dataDisplayedSF = 0; int oldDataSfIdx = -1, dataSfIdx = -1; //if the 'data' entity is a real ccPointCloud, we can even create a proper temporary SF for registration distances if (data->isA(CC_TYPES::POINT_CLOUD)) { ccPointCloud* pc = static_cast<ccPointCloud*>(data); dataDisplayedSF = pc->getCurrentDisplayedScalarField(); oldDataSfIdx = pc->getCurrentInScalarFieldIndex(); dataSfIdx = pc->getScalarFieldIndexByName(REGISTRATION_DISTS_SF); if (dataSfIdx < 0) dataSfIdx = pc->addScalarField(REGISTRATION_DISTS_SF); if (dataSfIdx >= 0) pc->setCurrentScalarField(dataSfIdx); else { ccLog::Error("[ICP] Couldn't create temporary scalar field! Not enough memory?"); return false; } } else { if (!dataCloud->enableScalarField()) { ccLog::Error("[ICP] Couldn't create temporary scalar field! Not enough memory?"); return false; } } //add a 'safety' margin to input ratio static double s_overlapMarginRatio = 0.2; finalOverlapRatio = std::max(finalOverlapRatio, 0.01); //1% minimum //do we need to reduce the input point cloud (so as to be close //to the theoretical number of overlapping points - but not too //low so as we are not registered yet ;) if (finalOverlapRatio < 1.0 - s_overlapMarginRatio) { //DGM we can now use 'approximate' distances as SAITO algorithm is exact (but with a coarse resolution) //level = 7 if < 1.000.000 //level = 8 if < 10.000.000 //level = 9 if > 10.000.000 int gridLevel = static_cast<int>(floor(log10(static_cast<double>(std::max(dataCloud->size(), modelCloud->size()))))) + 2; gridLevel = std::min(std::max(gridLevel,7),9); int result = -1; if (modelMesh) { CCLib::DistanceComputationTools::Cloud2MeshDistanceComputationParams c2mParams; c2mParams.octreeLevel = gridLevel; c2mParams.maxSearchDist = 0; c2mParams.useDistanceMap = true, c2mParams.signedDistances = false; c2mParams.flipNormals = false; c2mParams.multiThread = false; result = CCLib::DistanceComputationTools::computeCloud2MeshDistance(dataCloud, modelMesh, c2mParams, &pDlg); } else { result = CCLib::DistanceComputationTools::computeApproxCloud2CloudDistance( dataCloud, modelCloud, gridLevel, -1, &pDlg); } if (result < 0) { ccLog::Error("Failed to determine the max (overlap) distance (not enough memory?)"); return false; } //determine the max distance that (roughly) corresponds to the input overlap ratio ScalarType maxSearchDist = 0; { unsigned count = dataCloud->size(); std::vector<ScalarType> distances; try { distances.resize(count); } catch (const std::bad_alloc&) { ccLog::Error("Not enough memory!"); return false; } for (unsigned i=0; i<count; ++i) { distances[i] = dataCloud->getPointScalarValue(i); } SortAlgo(distances.begin(), distances.end()); //now look for the max value at 'finalOverlapRatio+margin' percent maxSearchDist = distances[static_cast<unsigned>(std::max(1.0,count*(finalOverlapRatio+s_overlapMarginRatio)))-1]; } //evntually select the points with distance below 'maxSearchDist' //(should roughly correspond to 'finalOverlapRatio + margin' percent) { CCLib::ReferenceCloud* refCloud = new CCLib::ReferenceCloud(dataCloud); cloudGarbage.add(refCloud); unsigned countBefore = dataCloud->size(); unsigned baseIncrement = static_cast<unsigned>(std::max(100.0,countBefore*finalOverlapRatio*0.05)); for (unsigned i=0; i<countBefore; ++i) { if (dataCloud->getPointScalarValue(i) <= maxSearchDist) { if ( refCloud->size() == refCloud->capacity() && !refCloud->reserve(refCloud->size() + baseIncrement) ) { ccLog::Error("Not enough memory!"); return false; } refCloud->addPointIndex(i); } } refCloud->resize(refCloud->size()); dataCloud = refCloud; unsigned countAfter = dataCloud->size(); double keptRatio = static_cast<double>(countAfter)/countBefore; ccLog::Print(QString("[ICP][Partial overlap] Selecting %1 points out of %2 (%3%) for registration").arg(countAfter).arg(countBefore).arg(static_cast<int>(100*keptRatio))); //update the relative 'final overlap' ratio finalOverlapRatio /= keptRatio; } } //weights CCLib::ScalarField* modelWeights = 0; CCLib::ScalarField* dataWeights = 0; { if (!modelMesh && useModelSFAsWeights) { if (modelCloud == dynamic_cast<CCLib::GenericIndexedCloudPersist*>(model) && model->isA(CC_TYPES::POINT_CLOUD)) { ccPointCloud* pc = static_cast<ccPointCloud*>(model); modelWeights = pc->getCurrentDisplayedScalarField(); if (!modelWeights) ccLog::Warning("[ICP] 'useDataSFAsWeights' is true but model has no displayed scalar field!"); } else { ccLog::Warning("[ICP] 'useDataSFAsWeights' is true but only point clouds scalar fields can be used as weights!"); } } if (useDataSFAsWeights) { if (!dataDisplayedSF) { if (dataCloud == (CCLib::GenericIndexedCloudPersist*)data && data->isA(CC_TYPES::POINT_CLOUD)) ccLog::Warning("[ICP] 'useDataSFAsWeights' is true but data has no displayed scalar field!"); else ccLog::Warning("[ICP] 'useDataSFAsWeights' is true but inly point clouds scalar fields can be used as weights!"); } else dataWeights = dataDisplayedSF; } } CCLib::ICPRegistrationTools::RESULT_TYPE result; CCLib::PointProjectionTools::Transformation transform; CCLib::ICPRegistrationTools::Parameters params; { params.convType = method; params.minRMSDecrease = minRMSDecrease; params.nbMaxIterations = maxIterationCount; params.adjustScale = adjustScale; params.filterOutFarthestPoints = removeFarthestPoints; params.samplingLimit = randomSamplingLimit; params.finalOverlapRatio = finalOverlapRatio; params.modelWeights = modelWeights; params.dataWeights = dataWeights; params.transformationFilters = filters; params.maxThreadCount = maxThreadCount; } result = CCLib::ICPRegistrationTools::Register( modelCloud, modelMesh, dataCloud, params, transform, finalRMS, finalPointCount, static_cast<CCLib::GenericProgressCallback*>(&pDlg)); if (result >= CCLib::ICPRegistrationTools::ICP_ERROR) { ccLog::Error("Registration failed: an error occurred (code %i)",result); } else if (result == CCLib::ICPRegistrationTools::ICP_APPLY_TRANSFO) { transMat = FromCCLibMatrix<PointCoordinateType,float>(transform.R, transform.T, transform.s); finalScale = transform.s; } //remove temporary SF (if any) if (dataSfIdx >= 0) { assert(data->isA(CC_TYPES::POINT_CLOUD)); ccPointCloud* pc = static_cast<ccPointCloud*>(data); pc->setCurrentScalarField(oldDataSfIdx); pc->deleteScalarField(dataSfIdx); dataSfIdx = -1; } return (result < CCLib::ICPRegistrationTools::ICP_ERROR); }
void ConnectionManager::addClient() { NewProtocol pDlg(this); if (pDlg.exec()) fill(); }
tbool CKSXML_Read_Project::Read_Project_From_Koblo(std::string sProject ) { // store project name std::string sProject_Name = gpApplication->Project_Name(); // clean project Reset_Project(); // clean parser Prepare_For_XML(); // read xml file tchar* pszBuff = NULL; tint32 iOutLen = 0; ine::IINetUtil::GetWebFile(NULL, "koblo.com", sProject.c_str(), &iOutLen, &pszBuff); if ((pszBuff) && (iOutLen > 0)) { // parse XML file in to TinyXml object tree mpTinyXMLDoc->Parse(pszBuff); printf(pszBuff); // pass the TinyXML DOM in to the DAW data structure //Pass_The_Project_Tag( mpTinyXMLDoc ); if(mbOpen_Dialog){ // get the project name from the xml file if (!Get_Project_Name_From_XML( mpTinyXMLDoc ) ) return false; tchar pszDefaultFolder[1024]; gpApplication->GetDefaultProjectFolder(pszDefaultFolder); // get default folder tchar pszDefault_Folder[1024]; gpApplication->GetDefaultProjectFolder(pszDefault_Folder); //std::string sProject_Name = gpApplication->Online_Project_Name(); // open new project dialog tchar pszProject_Folder[1024]; CAutoDelete<ge::ISaveAsDialog> pDlg(ge::ISaveAsDialog::Create()); // Don't browse into OS X bundles (special kind of folders) pDlg->SetBundleBehaviour(1); pDlg->DoDialog(pszProject_Folder, pszDefault_Folder, "", "", msTemp_Online_Project_Name.c_str() ); std::string sProject_Folder = pszProject_Folder; // user canceled operation if (pszProject_Folder[0] == 0){ // User cancelled - clean Reset_Project(); Prepare_For_XML(); } // continue else { // now pass the xml file Pass_The_Project_Tag( mpTinyXMLDoc ); // update path's and names for files and folders gpApplication->Update_Project_Name(sProject_Folder); // tbool bExists = IFile::Exists(sProject.c_str() , &bIsFolder); // create new folders for the project gpApplication->Create_Folders(); // create a new project file gpApplication->Create_Project_File(); // save project gpApplication->Write_XML_File_To_Disk(pszBuff); // prepare samples for download and decompression Prepare_Samples(); // download takes Download_Takes(); // decompress takes // How can samples be decompressed before they are downloaded? Decompress_Takes(); } } else{ // now pass the xml file Pass_The_Project_Tag( mpTinyXMLDoc ); // restore project name gpApplication->Project_Name(sProject_Name); // save project to disk gpApplication->Write_XML_File_To_Disk(pszBuff); // prepare samples for download and decompression Prepare_Samples(); // decompress takes Decompress_Takes(); // download takes Download_Takes(); } } else { // loading failed reload file from disk if any } ine::IINetUtil::ReleaseBuffer(&pszBuff); return true; }
void COldVideoRecvTestDlg::OnBnClickedButton3() { COldSetVideoEnahnceFlagDlg pDlg(this); pDlg.DoModal(); }
CC_FILE_ERROR AsciiFilter::loadCloudFromFormatedAsciiFile( const QString& filename, ccHObject& container, const AsciiOpenDlg::Sequence& openSequence, char separator, unsigned approximateNumberOfLines, qint64 fileSize, unsigned maxCloudSize, unsigned skipLines, LoadParameters& parameters, bool showLabelsIn2D/*=false*/) { //we may have to "slice" clouds when opening them if they are too big! maxCloudSize = std::min(maxCloudSize, CC_MAX_NUMBER_OF_POINTS_PER_CLOUD); unsigned cloudChunkSize = std::min(maxCloudSize, approximateNumberOfLines); unsigned cloudChunkPos = 0; unsigned chunkRank = 1; //we initialize the loading accelerator structure and point cloud int maxPartIndex = -1; cloudAttributesDescriptor cloudDesc = prepareCloud(openSequence, cloudChunkSize, maxPartIndex, separator, chunkRank); if (!cloudDesc.cloud) { return CC_FERR_NOT_ENOUGH_MEMORY; } //we re-open the file (ASCII mode) QFile file(filename); if (!file.open(QFile::ReadOnly)) { //we clear already initialized data clearStructure(cloudDesc); return CC_FERR_READING; } QTextStream stream(&file); //we skip lines as defined on input { for (unsigned i = 0; i < skipLines; ++i) { stream.readLine(); } } //progress indicator QScopedPointer<ccProgressDialog> pDlg(0); if (parameters.parentWidget) { pDlg.reset(new ccProgressDialog(true, parameters.parentWidget)); pDlg->setMethodTitle(QObject::tr("Open ASCII file [%1]").arg(filename)); pDlg->setInfo(QObject::tr("Approximate number of points: %1").arg(approximateNumberOfLines)); pDlg->start(); } CCLib::NormalizedProgress nprogress(pDlg.data(), approximateNumberOfLines); //buffers ScalarType D = 0; CCVector3d P(0, 0, 0); CCVector3d Pshift(0, 0, 0); CCVector3 N(0, 0, 0); ccColor::Rgb col; //other useful variables unsigned linesRead = 0; unsigned pointsRead = 0; CC_FILE_ERROR result = CC_FERR_NO_ERROR; //main process unsigned nextLimit = /*cloudChunkPos+*/cloudChunkSize; QString currentLine = stream.readLine(); while (!currentLine.isNull()) { ++linesRead; //comment if (currentLine.startsWith("//")) { currentLine = stream.readLine(); continue; } if (currentLine.size() == 0) { ccLog::Warning("[AsciiFilter::Load] Line %i is corrupted (empty)!",linesRead); currentLine = stream.readLine(); continue; } //if we have reached the max. number of points per cloud if (pointsRead == nextLimit) { ccLog::PrintDebug("[ASCII] Point %i -> end of chunk (%i points)",pointsRead,cloudChunkSize); //we re-evaluate the average line size { double averageLineSize = static_cast<double>(file.pos()) / (pointsRead + skipLines); double newNbOfLinesApproximation = std::max(1.0, static_cast<double>(fileSize) / averageLineSize - static_cast<double>(skipLines)); //if approximation is smaller than actual one, we add 2% by default if (newNbOfLinesApproximation <= pointsRead) { newNbOfLinesApproximation = std::max(static_cast<double>(cloudChunkPos + cloudChunkSize) + 1.0, static_cast<double>(pointsRead)* 1.02); } approximateNumberOfLines = static_cast<unsigned>(ceil(newNbOfLinesApproximation)); ccLog::PrintDebug("[ASCII] New approximate nb of lines: %i", approximateNumberOfLines); } //we try to resize actual clouds if (cloudChunkSize < maxCloudSize || approximateNumberOfLines - cloudChunkPos <= maxCloudSize) { ccLog::PrintDebug("[ASCII] We choose to enlarge existing clouds"); cloudChunkSize = std::min(maxCloudSize, approximateNumberOfLines - cloudChunkPos); if (!cloudDesc.cloud->reserve(cloudChunkSize)) { ccLog::Error("Not enough memory! Process stopped ..."); result = CC_FERR_NOT_ENOUGH_MEMORY; break; } } else //otherwise we have to create new clouds { ccLog::PrintDebug("[ASCII] We choose to instantiate new clouds"); //we store (and resize) actual cloud if (!cloudDesc.cloud->resize(cloudChunkSize)) ccLog::Warning("Memory reallocation failed ... some memory may have been wasted ..."); if (!cloudDesc.scalarFields.empty()) { for (unsigned k = 0; k < cloudDesc.scalarFields.size(); ++k) cloudDesc.scalarFields[k]->computeMinAndMax(); cloudDesc.cloud->setCurrentDisplayedScalarField(0); cloudDesc.cloud->showSF(true); } //we add this cloud to the output container container.addChild(cloudDesc.cloud); cloudDesc.reset(); //and create new one cloudChunkPos = pointsRead; cloudChunkSize = std::min(maxCloudSize, approximateNumberOfLines - cloudChunkPos); cloudDesc = prepareCloud(openSequence, cloudChunkSize, maxPartIndex, separator, ++chunkRank); if (!cloudDesc.cloud) { ccLog::Error("Not enough memory! Process stopped ..."); break; } cloudDesc.cloud->setGlobalShift(Pshift); } //we update the progress info if (pDlg) { nprogress.scale(approximateNumberOfLines, 100, true); pDlg->setInfo(QObject::tr("Approximate number of points: %1").arg(approximateNumberOfLines)); } nextLimit = cloudChunkPos+cloudChunkSize; } //we split current line QStringList parts = currentLine.split(separator,QString::SkipEmptyParts); int nParts = parts.size(); if (nParts > maxPartIndex) //fake loop for easy break { //read the point coordinates bool lineIsCorrupted = true; for (int step = 0; step < 1; ++step) //fake loop for easy break { bool ok = true; if (cloudDesc.xCoordIndex >= 0) { P.x = parts[cloudDesc.xCoordIndex].toDouble(&ok); if (!ok) { break; } } if (cloudDesc.yCoordIndex >= 0) { P.y = parts[cloudDesc.yCoordIndex].toDouble(&ok); if (!ok) { break; } } if (cloudDesc.zCoordIndex >= 0) { P.z = parts[cloudDesc.zCoordIndex].toDouble(&ok); if (!ok) { break; } } lineIsCorrupted = false; } if (lineIsCorrupted) { ccLog::Warning("[AsciiFilter::Load] Line %i is corrupted (non numerical value found)", linesRead); continue; } //first point: check for 'big' coordinates if (pointsRead == 0) { if (HandleGlobalShift(P, Pshift, parameters)) { cloudDesc.cloud->setGlobalShift(Pshift); ccLog::Warning("[ASCIIFilter::loadFile] Cloud has been recentered! Translation: (%.2f ; %.2f ; %.2f)", Pshift.x, Pshift.y, Pshift.z); } } //add point cloudDesc.cloud->addPoint(CCVector3::fromArray((P + Pshift).u)); //Normal vector if (cloudDesc.hasNorms) { if (cloudDesc.xNormIndex >= 0) N.x = static_cast<PointCoordinateType>(parts[cloudDesc.xNormIndex].toDouble()); if (cloudDesc.yNormIndex >= 0) N.y = static_cast<PointCoordinateType>(parts[cloudDesc.yNormIndex].toDouble()); if (cloudDesc.zNormIndex >= 0) N.z = static_cast<PointCoordinateType>(parts[cloudDesc.zNormIndex].toDouble()); cloudDesc.cloud->addNorm(N); } //Colors if (cloudDesc.hasRGBColors) { if (cloudDesc.iRgbaIndex >= 0) { const uint32_t rgb = parts[cloudDesc.iRgbaIndex].toInt(); col.r = ((rgb >> 16) & 0x0000ff); col.g = ((rgb >> 8) & 0x0000ff); col.b = ((rgb ) & 0x0000ff); } else if (cloudDesc.fRgbaIndex >= 0) { const float rgbf = parts[cloudDesc.fRgbaIndex].toFloat(); const uint32_t rgb = (uint32_t)(*((uint32_t*)&rgbf)); col.r = ((rgb >> 16) & 0x0000ff); col.g = ((rgb >> 8) & 0x0000ff); col.b = ((rgb ) & 0x0000ff); } else { if (cloudDesc.redIndex >= 0) { float multiplier = cloudDesc.hasFloatRGBColors[0] ? static_cast<float>(ccColor::MAX) : 1.0f; col.r = static_cast<ColorCompType>(parts[cloudDesc.redIndex].toFloat() * multiplier); } if (cloudDesc.greenIndex >= 0) { float multiplier = cloudDesc.hasFloatRGBColors[1] ? static_cast<float>(ccColor::MAX) : 1.0f; col.g = static_cast<ColorCompType>(parts[cloudDesc.greenIndex].toFloat() * multiplier); } if (cloudDesc.blueIndex >= 0) { float multiplier = cloudDesc.hasFloatRGBColors[2] ? static_cast<float>(ccColor::MAX) : 1.0f; col.b = static_cast<ColorCompType>(parts[cloudDesc.blueIndex].toFloat() * multiplier); } } cloudDesc.cloud->addRGBColor(col.rgb); }
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); const CCVector3d& globalShift = pc->getGlobalShift(); double globalScale = pc->getGlobalScale(); //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] = static_cast<float>(P->x); Pt.pos[1] = static_cast<float>(P->y); Pt.pos[2] = static_cast<float>(P->z); if (hasNorms) { const PointCoordinateType* N = pc->getPointNormal(i); Pt.normal[0] = static_cast<float>(N[0]); Pt.normal[1] = static_cast<float>(N[1]); Pt.normal[2] = static_cast<float>(N[2]); } cloud.push_back(Pt); } //manually set bounding box! Vec3f cbbMin,cbbMax; cbbMin[0] = static_cast<float>(bbMin[0]); cbbMin[1] = static_cast<float>(bbMin[1]); cbbMin[2] = static_cast<float>(bbMin[2]); cbbMax[0] = static_cast<float>(bbMax[0]); cbbMax[1] = static_cast<float>(bbMax[1]); cbbMax[2] = static_cast<float>(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 = static_cast<float>(rsdDlg.epsilonDoubleSpinBox->value()); ransacOptions.m_bitmapEpsilon = static_cast<float>(rsdDlg.bitmapEpsilonDoubleSpinBox->value()); ransacOptions.m_normalThresh = static_cast<float>(rsdDlg.normThreshDoubleSpinBox->value()); ransacOptions.m_probability = static_cast<float>(rsdDlg.probaDoubleSpinBox->value()); ransacOptions.m_minSupport = static_cast<unsigned>(rsdDlg.supportPointsSpinBox->value()); } if (!hasNorms) { QProgressDialog pDlg("Computing normals (please wait)",QString(),0,0,m_app->getMainWindow()); pDlg.setWindowTitle("Ransac Shape Detection"); pDlg.show(); QApplication::processEvents(); cloud.calcNormals(.01f * scale); if (pc->reserveTheNormsTable()) { for (size_t i=0; i<count; ++i) { Vec3f& Ni = cloud[i].normal; //normalize the vector in case of Vector3Tpl<float>::vnormalize(Ni); pc->addNorm(Ni[0],Ni[1],Ni[2]); } 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 ) { //progress dialog (Qtconcurrent::run can't be canceled!) QProgressDialog pDlg("Operation in progress (please wait)",QString(),0,0,m_app->getMainWindow()); pDlg.setWindowTitle("Ransac Shape Detection"); pDlg.show(); QApplication::processEvents(); //run in a separate thread s_detector = &detector; s_shapes = &shapes; s_cloud = &cloud; QFuture<void> future = QtConcurrent::run(doDetection); while (!future.isFinished()) { #if defined(CC_WINDOWS) ::Sleep(500); #else sleep(500); #endif pDlg.setValue(pDlg.value()+1); QApplication::processEvents(); } remaining = s_remainingPoints; pDlg.hide(); 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; size_t 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::fromArray(cloud[count-1-j].pos)); if (saveNormals) pcShape->addNorm(CCVector3::fromArray(cloud[count-1-j].normal).u); } //random color colorType col[3]; ccColor::Generator::Random(col); pcShape->setRGBColor(col); pcShape->showColors(true); pcShape->showNormals(saveNormals); pcShape->setVisible(true); pcShape->setGlobalShift(globalShift); pcShape->setGlobalScale(globalScale); //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/2); G += Y * (minY+dY/2); //we build matrix from these vectors ccGLMatrix glMat( CCVector3::fromArray(X.getValue()), CCVector3::fromArray(Y.getValue()), CCVector3::fromArray(N.getValue()), CCVector3::fromArray(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(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/2); 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::fromArray(X.getValue()), CCVector3::fromArray(Y.getValue()), CCVector3::fromArray(N.getValue()), CCVector3::fromArray(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 = CCVector3::fromArray(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::fromArray(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::fromArray(CA.getValue()); CCVector3 C = CCVector3::fromArray(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/2)*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::fromArray(CA.getValue()); CCVector3 C = CCVector3::fromArray(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(); } } }
CC_FILE_ERROR AsciiFilter::saveToFile(ccHObject* entity, QString filename, SaveParameters& parameters) { assert(entity && !filename.isEmpty()); AsciiSaveDlg* saveDialog = GetSaveDialog(parameters.parentWidget); assert(saveDialog); //if the dialog shouldn't be shown, we'll simply take the default values! if (parameters.alwaysDisplaySaveDialog && saveDialog->autoShow() && !saveDialog->exec()) { return CC_FERR_CANCELED_BY_USER; } if (!entity->isKindOf(CC_TYPES::POINT_CLOUD)) { if (entity->isA(CC_TYPES::HIERARCHY_OBJECT)) //multiple clouds? { QFileInfo fi(filename); QString extension = fi.suffix(); QString baseName = fi.completeBaseName(); QString path = fi.path(); unsigned count = entity->getChildrenNumber(); //we count the number of clouds first unsigned cloudCount = 0; { for (unsigned i = 0; i < count; ++i) { ccHObject* child = entity->getChild(i); if (child->isKindOf(CC_TYPES::POINT_CLOUD)) ++cloudCount; } } //we can now create the corresponding file(s) if (cloudCount > 1) { unsigned counter = 0; //disable the save dialog so that it doesn't appear again! AsciiSaveDlg* saveDialog = GetSaveDialog(); assert(saveDialog); bool autoShow = saveDialog->autoShow(); saveDialog->setAutoShow(false); for (unsigned i=0; i<count; ++i) { ccHObject* child = entity->getChild(i); if (child->isKindOf(CC_TYPES::POINT_CLOUD)) { QString subFilename = path+QString("/"); subFilename += QString(baseName).replace("cloudname",child->getName(),Qt::CaseInsensitive); counter++; assert(counter <= cloudCount); subFilename += QString("_%1").arg(cloudCount-counter,6,10,QChar('0')); if (!extension.isEmpty()) subFilename += QString(".") + extension; CC_FILE_ERROR result = saveToFile(entity->getChild(i),subFilename,parameters); if (result != CC_FERR_NO_ERROR) { return result; } else { ccLog::Print(QString("[ASCII] Cloud '%1' has been saved in: %2").arg(child->getName(),subFilename)); } } else { ccLog::Warning(QString("[ASCII] Entity '%1' can't be saved this way!").arg(child->getName())); } } //restore previous state saveDialog->setAutoShow(autoShow); return CC_FERR_NO_ERROR; } } else { return CC_FERR_BAD_ARGUMENT; } } QFile file(filename); if (!file.open(QFile::WriteOnly | QFile::Truncate)) return CC_FERR_WRITING; QTextStream stream(&file); ccGenericPointCloud* cloud = ccHObjectCaster::ToGenericPointCloud(entity); unsigned numberOfPoints = cloud->size(); bool writeColors = cloud->hasColors(); bool writeNorms = cloud->hasNormals(); std::vector<ccScalarField*> theScalarFields; if (cloud->isKindOf(CC_TYPES::POINT_CLOUD)) { ccPointCloud* ccCloud = static_cast<ccPointCloud*>(cloud); for (unsigned i = 0; i < ccCloud->getNumberOfScalarFields(); ++i) theScalarFields.push_back(static_cast<ccScalarField*>(ccCloud->getScalarField(i))); } bool writeSF = (theScalarFields.size() != 0); //progress dialog QScopedPointer<ccProgressDialog> pDlg(0); if (parameters.parentWidget) { pDlg.reset(new ccProgressDialog(true, parameters.parentWidget)); pDlg->setMethodTitle(QObject::tr("Saving cloud [%1]").arg(cloud->getName())); pDlg->setInfo(QObject::tr("Number of points: %1").arg(numberOfPoints)); pDlg->start(); } CCLib::NormalizedProgress nprogress(pDlg.data(), numberOfPoints); //output precision const int s_coordPrecision = saveDialog->coordsPrecision(); const int s_sfPrecision = saveDialog->sfPrecision(); const int s_nPrecision = 2+sizeof(PointCoordinateType); //other parameters bool saveColumnsHeader = saveDialog->saveColumnsNamesHeader(); bool savePointCountHeader = saveDialog->savePointCountHeader(); bool swapColorAndSFs = saveDialog->swapColorAndSF(); QChar separator(saveDialog->getSeparator()); bool saveFloatColors = saveDialog->saveFloatColors(); if (saveColumnsHeader) { QString header("//"); header.append(AsciiHeaderColumns::X()); header.append(separator); header.append(AsciiHeaderColumns::Y()); header.append(separator); header.append(AsciiHeaderColumns::Z()); if (writeColors && !swapColorAndSFs) { header.append(separator); header.append(saveFloatColors ? AsciiHeaderColumns::Rf() : AsciiHeaderColumns::R()); header.append(separator); header.append(saveFloatColors ? AsciiHeaderColumns::Gf() : AsciiHeaderColumns::G()); header.append(separator); header.append(saveFloatColors ? AsciiHeaderColumns::Bf() : AsciiHeaderColumns::B()); } if (writeSF) { //add each associated SF name for (std::vector<ccScalarField*>::const_iterator it = theScalarFields.begin(); it != theScalarFields.end(); ++it) { QString sfName((*it)->getName()); sfName.replace(separator, '_'); header.append(separator); header.append(sfName); } } if (writeColors && swapColorAndSFs) { header.append(separator); header.append(saveFloatColors ? AsciiHeaderColumns::Rf() : AsciiHeaderColumns::R()); header.append(separator); header.append(saveFloatColors ? AsciiHeaderColumns::Gf() : AsciiHeaderColumns::G()); header.append(separator); header.append(saveFloatColors ? AsciiHeaderColumns::Bf() : AsciiHeaderColumns::B()); } if (writeNorms) { header.append(separator); header.append(AsciiHeaderColumns::Nx()); header.append(separator); header.append(AsciiHeaderColumns::Ny()); header.append(separator); header.append(AsciiHeaderColumns::Nz()); } stream << header << "\n"; } if (savePointCountHeader) { stream << QString::number(numberOfPoints) << "\n"; } CC_FILE_ERROR result = CC_FERR_NO_ERROR; for (unsigned i = 0; i < numberOfPoints; ++i) { //line for the current point QString line; //write current point coordinates const CCVector3* P = cloud->getPoint(i); CCVector3d Pglobal = cloud->toGlobal3d<PointCoordinateType>(*P); line.append(QString::number(Pglobal.x, 'f', s_coordPrecision)); line.append(separator); line.append(QString::number(Pglobal.y, 'f', s_coordPrecision)); line.append(separator); line.append(QString::number(Pglobal.z, 'f', s_coordPrecision)); QString colorLine; if (writeColors) { //add rgb color const ColorCompType* col = cloud->getPointColor(i); if (saveFloatColors) { colorLine.append(separator); colorLine.append(QString::number(static_cast<double>(col[0]) / ccColor::MAX)); colorLine.append(separator); colorLine.append(QString::number(static_cast<double>(col[1]) / ccColor::MAX)); colorLine.append(separator); colorLine.append(QString::number(static_cast<double>(col[2]) / ccColor::MAX)); } else { colorLine.append(separator); colorLine.append(QString::number(col[0])); colorLine.append(separator); colorLine.append(QString::number(col[1])); colorLine.append(separator); colorLine.append(QString::number(col[2])); } if (!swapColorAndSFs) line.append(colorLine); } if (writeSF) { //add each associated SF values for (std::vector<ccScalarField*>::const_iterator it = theScalarFields.begin(); it != theScalarFields.end(); ++it) { line.append(separator); double sfVal = (*it)->getGlobalShift() + (*it)->getValue(i); line.append(QString::number(sfVal, 'f', s_sfPrecision)); } } if (writeColors && swapColorAndSFs) line.append(colorLine); if (writeNorms) { //add normal vector const CCVector3& N = cloud->getPointNormal(i); line.append(separator); line.append(QString::number(N.x, 'f', s_nPrecision)); line.append(separator); line.append(QString::number(N.y, 'f', s_nPrecision)); line.append(separator); line.append(QString::number(N.z, 'f', s_nPrecision)); } stream << line << "\n"; if (pDlg && !nprogress.oneStep()) { result = CC_FERR_CANCELED_BY_USER; break; } } return result; }
bool StereogramWidget::init(double angularStep_deg, ccHObject* entity, double resolution_deg/*=2.0*/) { m_angularStep_deg = angularStep_deg; if (m_densityGrid) delete m_densityGrid; m_densityGrid = 0; if (!entity) return false; ccProgressDialog pDlg(true); pDlg.setMethodTitle("Stereogram"); pDlg.setInfo("Preparing polar display..."); pDlg.start(); QApplication::processEvents(); size_t count = 0; ccHObject::Container facets; ccPointCloud* cloud = 0; //a set of facets? if (entity->isA(CC_TYPES::HIERARCHY_OBJECT)) { entity->filterChildren(facets,true,CC_TYPES::FACET); count = facets.size(); } //or a cloud? else if (entity->isA(CC_TYPES::POINT_CLOUD)) { cloud = static_cast<ccPointCloud*>(entity); if (cloud->hasNormals()) count = cloud->size(); } if (!count) return false; //pDlg.setMaximum(static_cast<int>(count)); CCLib::NormalizedProgress nProgress(&pDlg,static_cast<unsigned>(count)); //create the density grid FacetDensityGrid* densityGrid = new FacetDensityGrid(); densityGrid->step_deg = resolution_deg; densityGrid->step_R = 0.02; //dip steps (dip in [0,90]) //densityGrid->dSteps = static_cast<unsigned>(ceil(90.0 / densityGrid->step_deg)); //R steps (R in [0,1]) densityGrid->rSteps = static_cast<unsigned>(ceil(1.0 / densityGrid->step_R)); //dip direction steps (dip dir. in [0,360]) densityGrid->ddSteps = static_cast<unsigned>(ceil(360.0 / densityGrid->step_deg)); unsigned cellCount = densityGrid->rSteps * densityGrid->ddSteps; densityGrid->grid = new double[cellCount]; if (densityGrid->grid) { memset(densityGrid->grid,0,sizeof(double)*cellCount); CCVector3d Nmean(0,0,0); double surfaceSum = 0.0; for (size_t i=0; i<count; ++i) { CCVector3 N; double weight = 1.0; if (cloud) { N = cloud->getPointNormal(static_cast<unsigned>(i)); } else { ccFacet* facet = static_cast<ccFacet*>(facets[i]); N = facet->getNormal(); weight = facet->getSurface(); } Nmean.x += static_cast<double>(N.x) * weight; Nmean.y += static_cast<double>(N.y) * weight; Nmean.z += static_cast<double>(N.z) * weight; surfaceSum += weight; PointCoordinateType dipDir = 0, dip = 0; ccNormalVectors::ConvertNormalToDipAndDipDir(N,dip,dipDir); //unsigned iDip = static_cast<unsigned>(floor(static_cast<double>(dip)/densityGrid->step_deg)); //if (iDip == densityGrid->dSteps) // iDip--; unsigned iDipDir = static_cast<unsigned>(floor(static_cast<double>(dipDir)/densityGrid->step_deg)); if (iDipDir == densityGrid->ddSteps) iDipDir--; double dip_rad = dip * CC_DEG_TO_RAD; double R = sin(dip_rad) / (1.0 + cos(dip_rad)); unsigned iR = static_cast<unsigned>(floor(static_cast<double>(R)/densityGrid->step_R)); if (iR == densityGrid->rSteps) iR--; densityGrid->grid[iR + iDipDir * densityGrid->rSteps] += weight; //pDlg.setValue(static_cast<int>(i)); if (!nProgress.oneStep()) { //process cancelled by user delete densityGrid; return false; } } if (surfaceSum > 0) { Nmean.normalize(); CCVector3 N(static_cast<PointCoordinateType>(Nmean.x), static_cast<PointCoordinateType>(Nmean.y), static_cast<PointCoordinateType>(Nmean.z)); PointCoordinateType dipDir = 0, dip = 0; ccNormalVectors::ConvertNormalToDipAndDipDir(N,dip,dipDir); m_meanDipDir_deg = static_cast<double>(dipDir); m_meanDip_deg = static_cast<double>(dip); //set same value for the "filter" center m_clickDipDir_deg = m_meanDipDir_deg; m_clickDip_deg = m_meanDip_deg; } //compute min and max density { //DGM: only supported on C++x11! //std::pair<double*,double*> minmax = std::minmax_element(densityGrid->grid,densityGrid->grid+cellCount); //densityGrid->minMaxDensity[0] = *minmax.first; //densityGrid->minMaxDensity[1] = *minmax.second; densityGrid->minMaxDensity[0] = densityGrid->grid[0]; densityGrid->minMaxDensity[1] = densityGrid->grid[0]; for (unsigned j=1; j<cellCount; ++j) { if (densityGrid->grid[j] < densityGrid->minMaxDensity[0]) densityGrid->minMaxDensity[0] = densityGrid->grid[j]; else if (densityGrid->grid[j] > densityGrid->minMaxDensity[1]) densityGrid->minMaxDensity[1] = densityGrid->grid[j]; } } //pDlg.hide(); pDlg.stop(); QApplication::processEvents(); } else { //not enough memory! delete densityGrid; densityGrid = 0; } //replace old grid by new one! (even in case of failure! See below) m_densityGrid = densityGrid; update(); return true; }
void qCork::doAction() { assert(m_app); if (!m_app) return; const ccHObject::Container& selectedEntities = m_app->getSelectedEntities(); size_t selNum = selectedEntities.size(); if ( selNum != 2 || !selectedEntities[0]->isKindOf(CC_TYPES::MESH) || !selectedEntities[1]->isKindOf(CC_TYPES::MESH) ) { assert(false); m_app->dispToConsole("Select two and only two meshes!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } ccMesh* meshA = static_cast<ccMesh*>(selectedEntities[0]); ccMesh* meshB = static_cast<ccMesh*>(selectedEntities[1]); //show dialog to let the user choose the operation to perform ccCorkDlg cDlg(m_app->getMainWindow()); cDlg.setNames(meshA->getName(),meshB->getName()); if (!cDlg.exec()) return; if (cDlg.isSwapped()) std::swap(meshA,meshB); //try to convert both meshes to CorkMesh structures CorkMesh corkA; if (!ToCorkMesh(meshA, corkA, m_app)) return; CorkMesh corkB; if (!ToCorkMesh(meshB, corkB, m_app)) return; //launch process { //run in a separate thread QProgressDialog pDlg("Operation in progress",QString(),0,0,m_app->getMainWindow()); pDlg.setWindowTitle("Cork"); pDlg.show(); QApplication::processEvents(); s_params.app = m_app; s_params.corkA = &corkA; s_params.corkB = &corkB; s_params.nameA = meshA->getName(); s_params.nameB = meshB->getName(); s_params.operation = cDlg.getSelectedOperation(); QFuture<bool> future = QtConcurrent::run(doPerformBooleanOp); //wait until process is finished! while (!future.isFinished()) { #if defined(CC_WINDOWS) ::Sleep(500); #else usleep(500 * 1000); #endif pDlg.setValue(pDlg.value()+1); QApplication::processEvents(); } //just to be sure s_params.app = 0; s_params.corkA = s_params.corkB = 0; pDlg.hide(); QApplication::processEvents(); if (!future.result()) { if (m_app) m_app->dispToConsole(s_params.meshesAreOk ? "Computation failed!" : "Computation failed! (check console)",ccMainAppInterface::ERR_CONSOLE_MESSAGE); //an error occurred return; } } //convert the updated mesh (A) to a new ccMesh structure ccMesh* result = FromCorkMesh(corkA); if (result) { meshA->setEnabled(false); if (meshB->getDisplay() == meshA->getDisplay()) meshB->setEnabled(false); //set name QString opName; switch(cDlg.getSelectedOperation()) { case ccCorkDlg::UNION: opName = "union"; break; case ccCorkDlg::INTERSECT: opName = "isect"; break; case ccCorkDlg::DIFF: opName = "diff"; break; case ccCorkDlg::SYM_DIFF: opName = "sym_diff"; break; default: assert(false); break; } result->setName(QString("(%1).%2.(%3)").arg(meshA->getName()).arg(opName).arg(meshB->getName())); //normals bool hasNormals = false; if (meshA->hasTriNormals()) hasNormals = result->computePerTriangleNormals(); else if (meshA->hasNormals()) hasNormals = result->computePerVertexNormals(); meshA->showNormals(hasNormals && meshA->normalsShown()); result->setDisplay(meshA->getDisplay()); m_app->addToDB(result); result->redrawDisplay(); } //currently selected entities appearance may have changed! m_app->refreshAll(); }
ccHObject* qFacets::createFacets( ccPointCloud* cloud, CCLib::ReferenceCloudContainer& components, unsigned minPointsPerComponent, double maxEdgeLength, bool randomColors, bool& error) { if (!cloud) return 0; //we create a new group to store all input CCs as 'facets' ccHObject* ccGroup = new ccHObject(cloud->getName()+QString(" [facets]")); ccGroup->setDisplay(cloud->getDisplay()); ccGroup->setVisible(true); bool cloudHasNormal = cloud->hasNormals(); //number of input components size_t componentCount = components.size(); //progress notification ccProgressDialog pDlg(true,m_app->getMainWindow()); pDlg.setMethodTitle("Facets creation"); pDlg.setInfo(qPrintable(QString("Components: %1").arg(componentCount))); pDlg.setMaximum(static_cast<int>(componentCount)); pDlg.show(); QApplication::processEvents(); //for each component error = false; while (!components.empty()) { CCLib::ReferenceCloud* compIndexes = components.back(); components.pop_back(); //if it has enough points if (compIndexes && compIndexes->size() >= minPointsPerComponent) { ccPointCloud* facetCloud = cloud->partialClone(compIndexes); if (!facetCloud) { //not enough memory! error = true; delete facetCloud; facetCloud = 0; } else { ccFacet* facet = ccFacet::Create(facetCloud,static_cast<PointCoordinateType>(maxEdgeLength),true); if (facet) { QString facetName = QString("facet %1 (rms=%2)").arg(ccGroup->getChildrenNumber()).arg(facet->getRMS()); facet->setName(facetName); if (facet->getPolygon()) { facet->getPolygon()->enableStippling(false); facet->getPolygon()->showNormals(false); } if (facet->getContour()) { facet->getContour()->setGlobalScale(facetCloud->getGlobalScale()); facet->getContour()->setGlobalShift(facetCloud->getGlobalShift()); } //check the facet normal sign if (cloudHasNormal) { CCVector3 N = ccOctree::ComputeAverageNorm(compIndexes,cloud); if (N.dot(facet->getNormal()) < 0) facet->invertNormal(); } #ifdef _DEBUG facet->showNormalVector(true); #endif //shall we colorize it with a random color? ccColor::Rgb col, darkCol; if (randomColors) { col = ccColor::Generator::Random(); assert(c_darkColorRatio <= 1.0); darkCol.r = static_cast<ColorCompType>(static_cast<double>(col.r) * c_darkColorRatio); darkCol.g = static_cast<ColorCompType>(static_cast<double>(col.g) * c_darkColorRatio); darkCol.b = static_cast<ColorCompType>(static_cast<double>(col.b) * c_darkColorRatio); } else { //use normal-based HSV coloring CCVector3 N = facet->getNormal(); PointCoordinateType dip, dipDir; ccNormalVectors::ConvertNormalToDipAndDipDir(N, dip, dipDir); FacetsClassifier::GenerateSubfamilyColor(col,dip,dipDir,0,1,&darkCol); } facet->setColor(col); if (facet->getContour()) { facet->getContour()->setColor(darkCol); facet->getContour()->setWidth(2); } ccGroup->addChild(facet); } } if (compIndexes) delete compIndexes; compIndexes = 0; } pDlg.setValue(static_cast<int>(componentCount-components.size())); //QApplication::processEvents(); } if (ccGroup->getChildrenNumber() == 0) { delete ccGroup; ccGroup = 0; } return ccGroup; }
void qFacets::extractFacets(CellsFusionDlg::Algorithm algo) { //disclaimer accepted? if (!ShowDisclaimer(m_app)) return; assert(m_app); if (!m_app) return; //we expect a unique cloud as input const ccHObject::Container& selectedEntities = m_app->getSelectedEntities(); ccPointCloud* pc = (selectedEntities.size() == 1 ? ccHObjectCaster::ToPointCloud(selectedEntities.back()) : 0); if (!pc) { m_app->dispToConsole("Select one and only one point cloud!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } if (algo != CellsFusionDlg::ALGO_FAST_MARCHING && algo != CellsFusionDlg::ALGO_KD_TREE) { m_app->dispToConsole("Internal error: invalid algorithm type!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } //first time: we compute the max edge length automatically if (s_lastCloud != pc) { s_maxEdgeLength = static_cast<double>(pc->getOwnBB().getMinBoxDim())/50; s_minPointsPerFacet = std::max<unsigned>(pc->size() / 100000, 10); s_lastCloud = pc; } CellsFusionDlg fusionDlg(algo,m_app->getMainWindow()); if (algo == CellsFusionDlg::ALGO_FAST_MARCHING) fusionDlg.octreeLevelSpinBox->setCloud(pc); fusionDlg.octreeLevelSpinBox->setValue(s_octreeLevel); fusionDlg.useRetroProjectionCheckBox->setChecked(s_fmUseRetroProjectionError); fusionDlg.minPointsPerFacetSpinBox->setValue(s_minPointsPerFacet); fusionDlg.errorMeasureComboBox->setCurrentIndex(s_errorMeasureType); fusionDlg.maxRMSDoubleSpinBox->setValue(s_errorMaxPerFacet); fusionDlg.maxAngleDoubleSpinBox->setValue(s_kdTreeFusionMaxAngle_deg); fusionDlg.maxRelativeDistDoubleSpinBox->setValue(s_kdTreeFusionMaxRelativeDistance); fusionDlg.maxEdgeLengthDoubleSpinBox->setValue(s_maxEdgeLength); //"no normal" warning fusionDlg.noNormalWarningLabel->setVisible(!pc->hasNormals()); if (!fusionDlg.exec()) return; s_octreeLevel = fusionDlg.octreeLevelSpinBox->value(); s_fmUseRetroProjectionError = fusionDlg.useRetroProjectionCheckBox->isChecked(); s_minPointsPerFacet = fusionDlg.minPointsPerFacetSpinBox->value(); s_errorMeasureType = fusionDlg.errorMeasureComboBox->currentIndex(); s_errorMaxPerFacet = fusionDlg.maxRMSDoubleSpinBox->value(); s_kdTreeFusionMaxAngle_deg = fusionDlg.maxAngleDoubleSpinBox->value(); s_kdTreeFusionMaxRelativeDistance = fusionDlg.maxRelativeDistDoubleSpinBox->value(); s_maxEdgeLength = fusionDlg.maxEdgeLengthDoubleSpinBox->value(); //convert 'errorMeasureComboBox' index to enum CCLib::DistanceComputationTools::ERROR_MEASURES errorMeasure = CCLib::DistanceComputationTools::RMS; switch (s_errorMeasureType) { case 0: errorMeasure = CCLib::DistanceComputationTools::RMS; break; case 1: errorMeasure = CCLib::DistanceComputationTools::MAX_DIST_68_PERCENT; break; case 2: errorMeasure = CCLib::DistanceComputationTools::MAX_DIST_95_PERCENT; break; case 3: errorMeasure = CCLib::DistanceComputationTools::MAX_DIST_99_PERCENT; break; case 4: errorMeasure = CCLib::DistanceComputationTools::MAX_DIST; break; default: assert(false); break; } //create scalar field to host the fusion result const char c_defaultSFName[] = "facet indexes"; int sfIdx = pc->getScalarFieldIndexByName(c_defaultSFName); if (sfIdx < 0) sfIdx = pc->addScalarField(c_defaultSFName); if (sfIdx < 0) { m_app->dispToConsole("Couldn't allocate a new scalar field for computing fusion labels! Try to free some memory ...",ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } pc->setCurrentScalarField(sfIdx); //computation QElapsedTimer eTimer; eTimer.start(); ccProgressDialog pDlg(true,m_app->getMainWindow()); bool success = true; if (algo == CellsFusionDlg::ALGO_KD_TREE) { //we need a kd-tree QElapsedTimer eTimer; eTimer.start(); ccKdTree kdtree(pc); if (kdtree.build(s_errorMaxPerFacet/2,errorMeasure,s_minPointsPerFacet,1000,&pDlg)) { qint64 elapsedTime_ms = eTimer.elapsed(); m_app->dispToConsole(QString("[qFacets] Kd-tree construction timing: %1 s").arg(static_cast<double>(elapsedTime_ms)/1.0e3,0,'f',3),ccMainAppInterface::STD_CONSOLE_MESSAGE); success = ccKdTreeForFacetExtraction::FuseCells( &kdtree, s_errorMaxPerFacet, errorMeasure, s_kdTreeFusionMaxAngle_deg, static_cast<PointCoordinateType>(s_kdTreeFusionMaxRelativeDistance), true, &pDlg); } else { m_app->dispToConsole("Failed to build Kd-tree! (not enough memory?)",ccMainAppInterface::ERR_CONSOLE_MESSAGE); success = false; } } else if (algo == CellsFusionDlg::ALGO_FAST_MARCHING) { int result = FastMarchingForFacetExtraction::ExtractPlanarFacets( pc, static_cast<unsigned char>(s_octreeLevel), static_cast<ScalarType>(s_errorMaxPerFacet), errorMeasure, s_fmUseRetroProjectionError, &pDlg, pc->getOctree().data()); success = (result >= 0); } if (success) { pc->setCurrentScalarField(sfIdx); //for AutoSegmentationTools::extractConnectedComponents CCLib::ReferenceCloudContainer components; if (!CCLib::AutoSegmentationTools::extractConnectedComponents(pc,components)) { m_app->dispToConsole("Failed to extract fused components! (not enough memory?)",ccMainAppInterface::ERR_CONSOLE_MESSAGE); } else { //we remove the temporary scalar field (otherwise it will be copied to the sub-clouds!) ccScalarField* indexSF = static_cast<ccScalarField*>(pc->getScalarField(sfIdx)); indexSF->link(); //to prevent deletion below pc->deleteScalarField(sfIdx); sfIdx = -1; bool error = false; ccHObject* group = createFacets(pc,components,s_minPointsPerFacet,s_maxEdgeLength,false,error); if (group) { switch(algo) { case CellsFusionDlg::ALGO_KD_TREE: group->setName(group->getName() + QString(" [Kd-tree][error < %1][angle < %2 deg.]").arg(s_errorMaxPerFacet).arg(s_kdTreeFusionMaxAngle_deg)); break; case CellsFusionDlg::ALGO_FAST_MARCHING: group->setName(group->getName() + QString(" [FM][level %2][error < %1]").arg(s_octreeLevel).arg(s_errorMaxPerFacet)); break; default: break; } unsigned count = group->getChildrenNumber(); m_app->dispToConsole(QString("[qFacets] %1 facet(s) where created from cloud '%2'").arg(count).arg(pc->getName())); if (error) { m_app->dispToConsole("Error(s) occurred during the generation of facets! Result may be incomplete",ccMainAppInterface::ERR_CONSOLE_MESSAGE); } else { //we but back the scalar field if (indexSF) sfIdx = pc->addScalarField(indexSF); } //pc->setEnabled(false); m_app->addToDB(group); group->prepareDisplayForRefresh(); } else if (error) { m_app->dispToConsole("An error occurred during the generation of facets!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); } else { m_app->dispToConsole("No facet remains! Check the parameters (min size, etc.)",ccMainAppInterface::WRN_CONSOLE_MESSAGE); } } } else { m_app->dispToConsole("An error occurred during the fusion process!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); } if (sfIdx >= 0) { pc->getScalarField(sfIdx)->computeMinAndMax(); #ifdef _DEBUG pc->setCurrentDisplayedScalarField(sfIdx); pc->showSF(true); #endif } //currently selected entities appearance may have changed! m_app->redrawAll(); }
bool ccVolumeCalcTool::ComputeVolume( ccRasterGrid& grid, ccGenericPointCloud* ground, ccGenericPointCloud* ceil, const ccBBox& gridBox, unsigned char vertDim, double gridStep, unsigned gridWidth, unsigned gridHeight, ccRasterGrid::ProjectionType projectionType, ccRasterGrid::EmptyCellFillOption emptyCellFillStrategy, ccVolumeCalcTool::ReportInfo& reportInfo, double groundHeight = std::numeric_limits<double>::quiet_NaN(), double ceilHeight = std::numeric_limits<double>::quiet_NaN(), QWidget* parentWidget/*=0*/) { if ( gridStep <= 1.0e-8 || gridWidth == 0 || gridHeight == 0 || vertDim > 2) { assert(false); ccLog::Warning("[Volume] Invalid input parameters"); return false; } if (!ground && !ceil) { assert(false); ccLog::Warning("[Volume] No valid input cloud"); return false; } if (!gridBox.isValid()) { ccLog::Warning("[Volume] Invalid bounding-box"); return false; } //grid size unsigned gridTotalSize = gridWidth * gridHeight; if (gridTotalSize == 1) { if (parentWidget && QMessageBox::question(parentWidget, "Unexpected grid size", "The generated grid will only have 1 cell! Do you want to proceed anyway?", QMessageBox::Yes, QMessageBox::No) == QMessageBox::No) return false; } else if (gridTotalSize > 10000000) { if (parentWidget && QMessageBox::question(parentWidget, "Big grid size", "The generated grid will have more than 10.000.000 cells! Do you want to proceed anyway?", QMessageBox::Yes, QMessageBox::No) == QMessageBox::No) return false; } //memory allocation CCVector3d minCorner = CCVector3d::fromArray(gridBox.minCorner().u); if (!grid.init(gridWidth, gridHeight, gridStep, minCorner)) { //not enough memory return SendError("Not enough memory", parentWidget); } //progress dialog QScopedPointer<ccProgressDialog> pDlg(0); if (parentWidget) { pDlg.reset(new ccProgressDialog(true, parentWidget)); } ccRasterGrid groundRaster; if (ground) { if (!groundRaster.init(gridWidth, gridHeight, gridStep, minCorner)) { //not enough memory return SendError("Not enough memory", parentWidget); } if (groundRaster.fillWith( ground, vertDim, projectionType, emptyCellFillStrategy == ccRasterGrid::INTERPOLATE, ccRasterGrid::INVALID_PROJECTION_TYPE, pDlg.data())) { groundRaster.fillEmptyCells(emptyCellFillStrategy, groundHeight); ccLog::Print(QString("[Volume] Ground raster grid: size: %1 x %2 / heights: [%3 ; %4]").arg(groundRaster.width).arg(groundRaster.height).arg(groundRaster.minHeight).arg(groundRaster.maxHeight)); } else { return false; } } //ceil ccRasterGrid ceilRaster; if (ceil) { if (!ceilRaster.init(gridWidth, gridHeight, gridStep, minCorner)) { //not enough memory return SendError("Not enough memory", parentWidget); } if (ceilRaster.fillWith(ceil, vertDim, projectionType, emptyCellFillStrategy == ccRasterGrid::INTERPOLATE, ccRasterGrid::INVALID_PROJECTION_TYPE, pDlg.data())) { ceilRaster.fillEmptyCells(emptyCellFillStrategy, ceilHeight); ccLog::Print(QString("[Volume] Ceil raster grid: size: %1 x %2 / heights: [%3 ; %4]").arg(ceilRaster.width).arg(ceilRaster.height).arg(ceilRaster.minHeight).arg(ceilRaster.maxHeight)); } else { return false; } } //update grid and compute volume { if (pDlg) { pDlg->setMethodTitle(QObject::tr("Volume computation")); pDlg->setInfo(QObject::tr("Cells: %1 x %2").arg(grid.width).arg(grid.height)); pDlg->start(); pDlg->show(); QCoreApplication::processEvents(); } CCLib::NormalizedProgress nProgress(pDlg.data(), grid.width * grid.height); size_t ceilNonMatchingCount = 0; size_t groundNonMatchingCount = 0; size_t cellCount = 0; //at least one of the grid is based on a cloud grid.nonEmptyCellCount = 0; for (unsigned i = 0; i < grid.height; ++i) { for (unsigned j = 0; j < grid.width; ++j) { ccRasterCell& cell = grid.rows[i][j]; bool validGround = true; cell.minHeight = groundHeight; if (ground) { cell.minHeight = groundRaster.rows[i][j].h; validGround = std::isfinite(cell.minHeight); } bool validCeil = true; cell.maxHeight = ceilHeight; if (ceil) { cell.maxHeight = ceilRaster.rows[i][j].h; validCeil = std::isfinite(cell.maxHeight); } if (validGround && validCeil) { cell.h = cell.maxHeight - cell.minHeight; cell.nbPoints = 1; reportInfo.volume += cell.h; if (cell.h < 0) { reportInfo.removedVolume -= cell.h; } else if (cell.h > 0) { reportInfo.addedVolume += cell.h; } reportInfo.surface += 1.0; ++grid.nonEmptyCellCount; //= matching count ++cellCount; } else { if (validGround) { ++cellCount; ++groundNonMatchingCount; } else if (validCeil) { ++cellCount; ++ceilNonMatchingCount; } cell.h = std::numeric_limits<double>::quiet_NaN(); cell.nbPoints = 0; } cell.avgHeight = (groundHeight + ceilHeight) / 2; cell.stdDevHeight = 0; if (pDlg && !nProgress.oneStep()) { ccLog::Warning("[Volume] Process cancelled by the user"); return false; } } } grid.validCellCount = grid.nonEmptyCellCount; //count the average number of valid neighbors { size_t validNeighborsCount = 0; size_t count = 0; for (unsigned i = 1; i < grid.height - 1; ++i) { for (unsigned j = 1; j < grid.width - 1; ++j) { ccRasterCell& cell = grid.rows[i][j]; if (cell.h == cell.h) { for (unsigned k = i - 1; k <= i + 1; ++k) { for (unsigned l = j - 1; l <= j + 1; ++l) { if (k != i || l != j) { ccRasterCell& otherCell = grid.rows[k][l]; if (std::isfinite(otherCell.h)) { ++validNeighborsCount; } } } } ++count; } } } if (count) { reportInfo.averageNeighborsPerCell = static_cast<double>(validNeighborsCount) / count; } } reportInfo.matchingPrecent = static_cast<float>(grid.validCellCount * 100) / cellCount; reportInfo.groundNonMatchingPercent = static_cast<float>(groundNonMatchingCount * 100) / cellCount; reportInfo.ceilNonMatchingPercent = static_cast<float>(ceilNonMatchingCount * 100) / cellCount; float cellArea = static_cast<float>(grid.gridStep * grid.gridStep); reportInfo.volume *= cellArea; reportInfo.addedVolume *= cellArea; reportInfo.removedVolume *= cellArea; reportInfo.surface *= cellArea; } grid.setValid(true); return true; }
void CMatchingDlg::Execute(void) { int res; char msg[256]; m_FrameID = 0; g_free(m_CatFile); m_CatFile = NULL; g_free(m_SelectionName); m_SelectionName = NULL; m_FileList = NULL; // Restore path to catalog files gchar *fpath = CConfig::GetStr("MakeCatDlg", "Folder", NULL); if (fpath && *fpath!='\0' && g_file_test(fpath, G_FILE_TEST_IS_DIR)) gtk_entry_set_text(GTK_ENTRY(m_PathEntry), fpath); else { gchar *defpath = g_build_filename(get_user_data_dir(), "Catalog files", NULL); if (force_directory(defpath)) gtk_entry_set_text(GTK_ENTRY(m_PathEntry), defpath); g_free(defpath); } g_free(fpath); // Update list of frames ReadFrames(false, g_Project->GetInt("MatchingDlg", "Frame", 0)); // Update list of catalog files gchar *path = g_Project->GetStr("MatchingDlg", "File", NULL); if (!path) path = CConfig::GetStr("MatchingDlg", "File", NULL); ReadCatalogs(path); g_free(path); gtk_widget_show(m_UseFrame); // Check inputs if (gtk_tree_model_iter_n_children(GTK_TREE_MODEL(m_Frames), NULL)==0) { ShowError(m_pParent, "There are no frames usable as a reference frame."); return; } // Select reference frame or the first frame SetSelectMode(m_SelectMode); SetSortMode(m_FrameSort); UpdatePreview(true); UpdateControls(); if (gtk_dialog_run(GTK_DIALOG(m_pDlg))!=GTK_RESPONSE_ACCEPT) return; gtk_widget_hide(m_pDlg); g_Project->SetInt("MatchingDlg", "Select", m_SelectMode); if (m_SelectMode == REFERENCE_FRAME) g_Project->SetInt("MatchingDlg", "Frame", m_FrameID); else { g_Project->SetStr("MatchingDlg", "File", m_CatFile); CConfig::SetStr("MatchingDlg", "File", m_CatFile); } g_Project->ClearReference(); // Always all files gtk_tree_model_foreach(g_Project->FileList(), GtkTreeModelForeachFunc(make_list), &m_FileList); CProgressDlg pDlg(m_pParent, "Matching photometry files"); pDlg.SetMinMax(0, g_list_length(m_FileList)); res = pDlg.Execute(ExecuteProc, this); if (res!=0) { char *msg = cmpack_formaterror(res); ShowError(m_pParent, msg, true); cmpack_free(msg); } else if (m_OutFiles==0) { ShowError(m_pParent, "No file was successfully processed.", true); } else if (m_OutFiles!=m_InFiles) { sprintf(msg, "%d file(s) were successfully processed, %d file(s) failed.", m_OutFiles, m_InFiles-m_OutFiles); ShowWarning(m_pParent, msg, true); } else { sprintf(msg, "All %d file(s) were successfully processed.", m_OutFiles); ShowInformation(m_pParent, msg, true); } // Free allocated memory g_list_foreach(m_FileList, (GFunc)gtk_tree_row_reference_free, NULL); g_list_free(m_FileList); m_FileList = NULL; g_free(m_CatFile); m_CatFile = NULL; g_free(m_SelectionName); m_SelectionName = NULL; }
bool ccPointPairRegistrationDlg::convertToSphereCenter(CCVector3d& P, ccHObject* entity, PointCoordinateType& sphereRadius) { sphereRadius = -PC_ONE; if ( !entity || !useSphereToolButton->isChecked() || !entity->isKindOf(CC_TYPES::POINT_CLOUD) ) //only works with cloud right now { //nothing to do return true; } //we'll now try to detect the sphere double searchRadius = radiusDoubleSpinBox->value(); double maxRMSPercentage = maxRmsSpinBox->value() / 100.0; ccGenericPointCloud* cloud = static_cast<ccGenericPointCloud*>(entity); assert(cloud); //crop points inside a box centered on the current point ccBBox box; box.add(CCVector3::fromArray((P - CCVector3d(1,1,1)*searchRadius).u)); box.add(CCVector3::fromArray((P + CCVector3d(1,1,1)*searchRadius).u)); CCLib::ReferenceCloud* part = cloud->crop(box,true); bool success = false; if (part && part->size() > 16) { PointCoordinateType radius; CCVector3 C; double rms; ccProgressDialog pDlg(true, this); //first roughly search for the sphere if (CCLib::GeometricalAnalysisTools::detectSphereRobust(part,0.5,C,radius,rms,&pDlg,0.9)) { if (radius / searchRadius < 0.5 || radius / searchRadius > 2.0) { ccLog::Warning(QString("[ccPointPairRegistrationDlg] Detected sphere radius (%1) is too far from search radius!").arg(radius)); } else { //now look again (more precisely) { delete part; box.clear(); box.add(C - CCVector3(1,1,1)*radius*static_cast<PointCoordinateType>(1.05)); //add 5% box.add(C + CCVector3(1,1,1)*radius*static_cast<PointCoordinateType>(1.05)); //add 5% part = cloud->crop(box,true); if (part && part->size() > 16) CCLib::GeometricalAnalysisTools::detectSphereRobust(part,0.5,C,radius,rms,&pDlg,0.99); } ccLog::Print(QString("[ccPointPairRegistrationDlg] Detected sphere radius = %1 (rms = %2)").arg(radius).arg(rms)); if (radius / searchRadius < 0.5 || radius / searchRadius > 2.0) { ccLog::Warning("[ccPointPairRegistrationDlg] Sphere radius is too far from search radius!"); } else if (rms / searchRadius >= maxRMSPercentage) { ccLog::Warning("[ccPointPairRegistrationDlg] RMS is too high!"); } else { sphereRadius = radius; P = CCVector3d::fromArray(C.u); success = true; } } } else { ccLog::Warning("[ccPointPairRegistrationDlg] Failed to fit a sphere around the picked point!"); } } else { //not enough memory? No points inside the ccLog::Warning("[ccPointPairRegistrationDlg] Failed to crop points around the picked point?!"); } if (part) delete part; return success; }
CC_FILE_ERROR ObjFilter::loadFile(QString filename, ccHObject& container, LoadParameters& parameters) { ccLog::Print(QString("[OBJ] ") + filename); //open file QFile file(filename); if (!file.open(QFile::ReadOnly)) return CC_FERR_READING; QTextStream stream(&file); //current vertex shift CCVector3d Pshift(0,0,0); //vertices ccPointCloud* vertices = new ccPointCloud("vertices"); int pointsRead = 0; //facets unsigned int facesRead = 0; unsigned int totalFacesRead = 0; int maxVertexIndex = -1; //base mesh ccMesh* baseMesh = new ccMesh(vertices); baseMesh->setName(QFileInfo(filename).baseName()); //we need some space already reserved! if (!baseMesh->reserve(128)) { ccLog::Error("Not engouh memory!"); return CC_FERR_NOT_ENOUGH_MEMORY; } //groups (starting index + name) std::vector<std::pair<unsigned,QString> > groups; //materials ccMaterialSet* materials = 0; bool hasMaterial = false; int currentMaterial = -1; bool currentMaterialDefined = false; bool materialsLoadFailed = true; //texture coordinates TextureCoordsContainer* texCoords = 0; bool hasTexCoords = false; int texCoordsRead = 0; int maxTexCoordIndex = -1; //normals NormsIndexesTableType* normals = 0; int normsRead = 0; bool normalsPerFacet = false; int maxTriNormIndex = -1; //progress dialog ccProgressDialog pDlg(true); pDlg.setMethodTitle("OBJ file"); pDlg.setInfo("Loading in progress..."); pDlg.setRange(0,static_cast<int>(file.size())); pDlg.show(); QApplication::processEvents(); //common warnings that can appear multiple time (we avoid to send too many messages to the console!) enum OBJ_WARNINGS { INVALID_NORMALS = 0, INVALID_INDEX = 1, NOT_ENOUGH_MEMORY = 2, INVALID_LINE = 3, CANCELLED_BY_USER = 4, }; bool objWarnings[5] = { false, false, false, false, false }; bool error = false; try { unsigned lineCount = 0; unsigned polyCount = 0; QString currentLine = stream.readLine(); while (!currentLine.isNull()) { if ((++lineCount % 2048) == 0) { if (pDlg.wasCanceled()) { error = true; objWarnings[CANCELLED_BY_USER] = true; break; } pDlg.setValue(static_cast<int>(file.pos())); QApplication::processEvents(); } QStringList tokens = QString(currentLine).split(QRegExp("\\s+"),QString::SkipEmptyParts); //skip comments & empty lines if( tokens.empty() || tokens.front().startsWith('/',Qt::CaseInsensitive) || tokens.front().startsWith('#',Qt::CaseInsensitive) ) { currentLine = stream.readLine(); continue; } /*** new vertex ***/ if (tokens.front() == "v") { //reserve more memory if necessary if (vertices->size() == vertices->capacity()) { if (!vertices->reserve(vertices->capacity()+MAX_NUMBER_OF_ELEMENTS_PER_CHUNK)) { objWarnings[NOT_ENOUGH_MEMORY] = true; error = true; break; } } //malformed line? if (tokens.size() < 4) { objWarnings[INVALID_LINE] = true; error = true; break; } CCVector3d Pd( tokens[1].toDouble(), tokens[2].toDouble(), tokens[3].toDouble() ); //first point: check for 'big' coordinates if (pointsRead == 0) { if (HandleGlobalShift(Pd,Pshift,parameters)) { vertices->setGlobalShift(Pshift); ccLog::Warning("[OBJ] Cloud has been recentered! Translation: (%.2f,%.2f,%.2f)",Pshift.x,Pshift.y,Pshift.z); } } //shifted point CCVector3 P = CCVector3::fromArray((Pd + Pshift).u); vertices->addPoint(P); ++pointsRead; } /*** new vertex texture coordinates ***/ else if (tokens.front() == "vt") { //create and reserve memory for tex. coords container if necessary if (!texCoords) { texCoords = new TextureCoordsContainer(); texCoords->link(); } if (texCoords->currentSize() == texCoords->capacity()) { if (!texCoords->reserve(texCoords->capacity() + MAX_NUMBER_OF_ELEMENTS_PER_CHUNK)) { objWarnings[NOT_ENOUGH_MEMORY] = true; error = true; break; } } //malformed line? if (tokens.size() < 2) { objWarnings[INVALID_LINE] = true; error = true; break; } float T[2] = { T[0] = tokens[1].toFloat(), 0 }; if (tokens.size() > 2) //OBJ specification allows for only one value!!! { T[1] = tokens[2].toFloat(); } texCoords->addElement(T); ++texCoordsRead; } /*** new vertex normal ***/ else if (tokens.front() == "vn") //--> in fact it can also be a facet normal!!! { //create and reserve memory for normals container if necessary if (!normals) { normals = new NormsIndexesTableType; normals->link(); } if (normals->currentSize() == normals->capacity()) { if (!normals->reserve(normals->capacity() + MAX_NUMBER_OF_ELEMENTS_PER_CHUNK)) { objWarnings[NOT_ENOUGH_MEMORY] = true; error = true; break; } } //malformed line? if (tokens.size() < 4) { objWarnings[INVALID_LINE] = true; error = true; break; } CCVector3 N(static_cast<PointCoordinateType>(tokens[1].toDouble()), static_cast<PointCoordinateType>(tokens[2].toDouble()), static_cast<PointCoordinateType>(tokens[3].toDouble())); if (fabs(N.norm2() - 1.0) > 0.005) { objWarnings[INVALID_NORMALS] = true; N.normalize(); } CompressedNormType nIndex = ccNormalVectors::GetNormIndex(N.u); normals->addElement(nIndex); //we don't know yet if it's per-vertex or per-triangle normal... ++normsRead; } /*** new group ***/ else if (tokens.front() == "g" || tokens.front() == "o") { //update new group index facesRead = 0; //get the group name QString groupName = (tokens.size() > 1 && !tokens[1].isEmpty() ? tokens[1] : "default"); for (int i=2; i<tokens.size(); ++i) //multiple parts? groupName.append(QString(" ")+tokens[i]); //push previous group descriptor (if none was pushed) if (groups.empty() && totalFacesRead > 0) groups.push_back(std::pair<unsigned,QString>(0,"default")); //push new group descriptor if (!groups.empty() && groups.back().first == totalFacesRead) groups.back().second = groupName; //simply replace the group name if the previous group was empty! else groups.push_back(std::pair<unsigned,QString>(totalFacesRead,groupName)); polyCount = 0; //restart polyline count at 0! } /*** new face ***/ else if (tokens.front().startsWith('f')) { //malformed line? if (tokens.size() < 4) { objWarnings[INVALID_LINE] = true; currentLine = stream.readLine(); continue; //error = true; //break; } //read the face elements (singleton, pair or triplet) std::vector<facetElement> currentFace; { for (int i=1; i<tokens.size(); ++i) { QStringList vertexTokens = tokens[i].split('/'); if (vertexTokens.size() == 0 || vertexTokens[0].isEmpty()) { objWarnings[INVALID_LINE] = true; error = true; break; } else { //new vertex facetElement fe; //(0,0,0) by default fe.vIndex = vertexTokens[0].toInt(); if (vertexTokens.size() > 1 && !vertexTokens[1].isEmpty()) fe.tcIndex = vertexTokens[1].toInt(); if (vertexTokens.size() > 2 && !vertexTokens[2].isEmpty()) fe.nIndex = vertexTokens[2].toInt(); currentFace.push_back(fe); } } } if (error) break; if (currentFace.size() < 3) { ccLog::Warning("[OBJ] Malformed file: polygon on line %1 has less than 3 vertices!",lineCount); error = true; break; } //first vertex std::vector<facetElement>::iterator A = currentFace.begin(); //the very first vertex of the group tells us about the whole sequence if (facesRead == 0) { //we have a tex. coord index as second vertex element! if (!hasTexCoords && A->tcIndex != 0 && !materialsLoadFailed) { if (!baseMesh->reservePerTriangleTexCoordIndexes()) { objWarnings[NOT_ENOUGH_MEMORY] = true; error = true; break; } for (unsigned int i=0; i<totalFacesRead; ++i) baseMesh->addTriangleTexCoordIndexes(-1, -1, -1); hasTexCoords = true; } //we have a normal index as third vertex element! if (!normalsPerFacet && A->nIndex != 0) { //so the normals are 'per-facet' if (!baseMesh->reservePerTriangleNormalIndexes()) { objWarnings[NOT_ENOUGH_MEMORY] = true; error = true; break; } for (unsigned int i=0; i<totalFacesRead; ++i) baseMesh->addTriangleNormalIndexes(-1, -1, -1); normalsPerFacet = true; } } //we process all vertices accordingly for (std::vector<facetElement>::iterator it = currentFace.begin() ; it!=currentFace.end(); ++it) { facetElement& vertex = *it; //vertex index { if (!vertex.updatePointIndex(pointsRead)) { objWarnings[INVALID_INDEX] = true; error = true; break; } if (vertex.vIndex > maxVertexIndex) maxVertexIndex = vertex.vIndex; } //should we have a tex. coord index as second vertex element? if (hasTexCoords && currentMaterialDefined) { if (!vertex.updateTexCoordIndex(texCoordsRead)) { objWarnings[INVALID_INDEX] = true; error = true; break; } if (vertex.tcIndex > maxTexCoordIndex) maxTexCoordIndex = vertex.tcIndex; } //should we have a normal index as third vertex element? if (normalsPerFacet) { if (!vertex.updateNormalIndex(normsRead)) { objWarnings[INVALID_INDEX] = true; error = true; break; } if (vertex.nIndex > maxTriNormIndex) maxTriNormIndex = vertex.nIndex; } } //don't forget material (common for all vertices) if (currentMaterialDefined && !materialsLoadFailed) { if (!hasMaterial) { if (!baseMesh->reservePerTriangleMtlIndexes()) { objWarnings[NOT_ENOUGH_MEMORY] = true; error = true; break; } for (unsigned int i=0; i<totalFacesRead; ++i) baseMesh->addTriangleMtlIndex(-1); hasMaterial = true; } } if (error) break; //Now, let's tesselate the whole polygon //FIXME: yeah, we do very ulgy tesselation here! std::vector<facetElement>::const_iterator B = A+1; std::vector<facetElement>::const_iterator C = B+1; for ( ; C != currentFace.end(); ++B,++C) { //need more space? if (baseMesh->size() == baseMesh->capacity()) { if (!baseMesh->reserve(baseMesh->size()+128)) { objWarnings[NOT_ENOUGH_MEMORY] = true; error = true; break; } } //push new triangle baseMesh->addTriangle(A->vIndex, B->vIndex, C->vIndex); ++facesRead; ++totalFacesRead; if (hasMaterial) baseMesh->addTriangleMtlIndex(currentMaterial); if (hasTexCoords) baseMesh->addTriangleTexCoordIndexes(A->tcIndex, B->tcIndex, C->tcIndex); if (normalsPerFacet) baseMesh->addTriangleNormalIndexes(A->nIndex, B->nIndex, C->nIndex); } } /*** polyline ***/ else if (tokens.front().startsWith('l')) { //malformed line? if (tokens.size() < 3) { objWarnings[INVALID_LINE] = true; currentLine = stream.readLine(); continue; } //read the face elements (singleton, pair or triplet) ccPolyline* polyline = new ccPolyline(vertices); if (!polyline->reserve(static_cast<unsigned>(tokens.size()-1))) { //not enough memory objWarnings[NOT_ENOUGH_MEMORY] = true; delete polyline; polyline = 0; currentLine = stream.readLine(); continue; } for (int i=1; i<tokens.size(); ++i) { //get next polyline's vertex index QStringList vertexTokens = tokens[i].split('/'); if (vertexTokens.size() == 0 || vertexTokens[0].isEmpty()) { objWarnings[INVALID_LINE] = true; error = true; break; } else { int index = vertexTokens[0].toInt(); //we ignore normal index (if any!) if (!UpdatePointIndex(index,pointsRead)) { objWarnings[INVALID_INDEX] = true; error = true; break; } polyline->addPointIndex(index); } } if (error) { delete polyline; polyline = 0; break; } polyline->setVisible(true); QString name = groups.empty() ? QString("Line") : groups.back().second+QString(".line"); polyline->setName(QString("%1 %2").arg(name).arg(++polyCount)); vertices->addChild(polyline); } /*** material ***/ else if (tokens.front() == "usemtl") //see 'MTL file' below { if (materials) //otherwise we have failed to load MTL file!!! { QString mtlName = currentLine.mid(7).trimmed(); //DGM: in case there's space characters in the material name, we must read it again from the original line buffer //QString mtlName = (tokens.size() > 1 && !tokens[1].isEmpty() ? tokens[1] : ""); currentMaterial = (!mtlName.isEmpty() ? materials->findMaterialByName(mtlName) : -1); currentMaterialDefined = true; } } /*** material file (MTL) ***/ else if (tokens.front() == "mtllib") { //malformed line? if (tokens.size() < 2 || tokens[1].isEmpty()) { objWarnings[INVALID_LINE] = true; } else { //we build the whole MTL filename + path //DGM: in case there's space characters in the filename, we must read it again from the original line buffer //QString mtlFilename = tokens[1]; QString mtlFilename = currentLine.mid(7).trimmed(); ccLog::Print(QString("[OBJ] Material file: ")+mtlFilename); QString mtlPath = QFileInfo(filename).canonicalPath(); //we try to load it if (!materials) { materials = new ccMaterialSet("materials"); materials->link(); } size_t oldSize = materials->size(); QStringList errors; if (ccMaterialSet::ParseMTL(mtlPath,mtlFilename,*materials,errors)) { ccLog::Print("[OBJ] %i materials loaded",materials->size()-oldSize); materialsLoadFailed = false; } else { ccLog::Error(QString("[OBJ] Failed to load material file! (should be in '%1')").arg(mtlPath+'/'+QString(mtlFilename))); materialsLoadFailed = true; } if (!errors.empty()) { for (int i=0; i<errors.size(); ++i) ccLog::Warning(QString("[OBJ::Load::MTL parser] ")+errors[i]); } if (materials->empty()) { materials->release(); materials=0; materialsLoadFailed = true; } } } ///*** shading group ***/ //else if (tokens.front() == "s") //{ // //ignored! //} if (error) break; currentLine = stream.readLine(); } } catch (const std::bad_alloc&) { //not enough memory objWarnings[NOT_ENOUGH_MEMORY] = true; error = true; } file.close(); //1st check if (!error && pointsRead == 0) { //of course if there's no vertex, that's the end of the story ... ccLog::Warning("[OBJ] Malformed file: no vertex in file!"); error = true; } if (!error) { ccLog::Print("[OBJ] %i points, %u faces",pointsRead,totalFacesRead); if (texCoordsRead > 0 || normsRead > 0) ccLog::Print("[OBJ] %i tex. coords, %i normals",texCoordsRead,normsRead); //do some cleaning vertices->shrinkToFit(); if (normals) normals->shrinkToFit(); if (texCoords) texCoords->shrinkToFit(); if (baseMesh->size() == 0) { delete baseMesh; baseMesh = 0; } else { baseMesh->shrinkToFit(); } if ( maxVertexIndex >= pointsRead || maxTexCoordIndex >= texCoordsRead || maxTriNormIndex >= normsRead) { //hum, we've got a problem here ccLog::Warning("[OBJ] Malformed file: indexes go higher than the number of elements! (v=%i/tc=%i/n=%i)",maxVertexIndex,maxTexCoordIndex,maxTriNormIndex); if (maxVertexIndex >= pointsRead) { error = true; } else { objWarnings[INVALID_INDEX] = true; if (maxTexCoordIndex >= texCoordsRead) { texCoords->release(); texCoords = 0; materials->release(); materials = 0; } if (maxTriNormIndex >= normsRead) { normals->release(); normals = 0; } } } if (!error && baseMesh) { if (normals && normalsPerFacet) { baseMesh->setTriNormsTable(normals); baseMesh->showTriNorms(true); } if (materials) { baseMesh->setMaterialSet(materials); baseMesh->showMaterials(true); } if (texCoords) { if (materials) { baseMesh->setTexCoordinatesTable(texCoords); } else { ccLog::Warning("[OBJ] Texture coordinates were defined but no material could be loaded!"); } } //normals: if the obj file doesn't provide any, should we compute them? if (!normals) { //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 (!materials && !baseMesh->hasColors()) //yes if no material is available! //{ // ccLog::Print("[OBJ] Mesh has no normal! We will compute them automatically"); // baseMesh->computeNormals(); // baseMesh->showNormals(true); //} //else { ccLog::Warning("[OBJ] Mesh has no normal! You can manually compute them (select it then call \"Edit > Normals > Compute\")"); } } //create sub-meshes if necessary ccLog::Print("[OBJ] 1 mesh loaded - %i group(s)", groups.size()); if (groups.size() > 1) { for (size_t i=0; i<groups.size(); ++i) { const QString& groupName = groups[i].second; unsigned startIndex = groups[i].first; unsigned endIndex = (i+1 == groups.size() ? baseMesh->size() : groups[i+1].first); if (startIndex == endIndex) { continue; } ccSubMesh* subTri = new ccSubMesh(baseMesh); if (subTri->reserve(endIndex-startIndex)) { subTri->addTriangleIndex(startIndex,endIndex); subTri->setName(groupName); subTri->showMaterials(baseMesh->materialsShown()); subTri->showNormals(baseMesh->normalsShown()); subTri->showTriNorms(baseMesh->triNormsShown()); //subTri->showColors(baseMesh->colorsShown()); //subTri->showWired(baseMesh->isShownAsWire()); baseMesh->addChild(subTri); } else { delete subTri; subTri = 0; objWarnings[NOT_ENOUGH_MEMORY] = true; } } baseMesh->setVisible(false); vertices->setLocked(true); } baseMesh->addChild(vertices); //DGM: we can't deactive the vertices if it has children! (such as polyline) if (vertices->getChildrenNumber() != 0) vertices->setVisible(false); else vertices->setEnabled(false); container.addChild(baseMesh); } if (!baseMesh && vertices->size() != 0) { //no (valid) mesh! container.addChild(vertices); //we hide the vertices if the entity has children (probably polylines!) if (vertices->getChildrenNumber() != 0) { vertices->setVisible(false); } } //special case: normals held by cloud! if (normals && !normalsPerFacet) { if (normsRead == pointsRead) //must be 'per-vertex' normals { vertices->setNormsTable(normals); if (baseMesh) baseMesh->showNormals(true); } else { ccLog::Warning("File contains normals which seem to be neither per-vertex nor per-face!!! We had to ignore them..."); } } } if (error) { if (baseMesh) delete baseMesh; if (vertices) delete vertices; } //release shared structures if (normals) { normals->release(); normals = 0; } if (texCoords) { texCoords->release(); texCoords = 0; } if (materials) { materials->release(); materials = 0; } pDlg.close(); //potential warnings if (objWarnings[INVALID_NORMALS]) ccLog::Warning("[OBJ] Some normals in file were invalid. You should re-compute them (select entity, then \"Edit > Normals > Compute\")"); if (objWarnings[INVALID_INDEX]) ccLog::Warning("[OBJ] File is malformed! Check indexes..."); if (objWarnings[NOT_ENOUGH_MEMORY]) ccLog::Warning("[OBJ] Not enough memory!"); if (objWarnings[INVALID_LINE]) ccLog::Warning("[OBJ] File is malformed! Missing data."); if (error) { if (objWarnings[NOT_ENOUGH_MEMORY]) return CC_FERR_NOT_ENOUGH_MEMORY; else if (objWarnings[CANCELLED_BY_USER]) return CC_FERR_CANCELED_BY_USER; else return CC_FERR_MALFORMED_FILE; } else { return CC_FERR_NO_ERROR; } }
CC_FILE_ERROR BinFilter::loadFile(QString filename, ccHObject& container, LoadParameters& parameters) { ccLog::Print(QString("[BIN] Opening file '%1'...").arg(filename)); //opening file QFile in(filename); if (!in.open(QIODevice::ReadOnly)) return CC_FERR_READING; uint32_t firstBytes = 0; if (in.read((char*)&firstBytes,4) < 0) return CC_FERR_READING; bool v1 = (strncmp((char*)&firstBytes,"CCB",3) != 0); if (v1) { return LoadFileV1(in, container, static_cast<unsigned>(firstBytes), parameters); //firstBytes == number of scans for V1 files! } else { //Since ver 2.5.2, the 4th character of the header corresponds to 'load flags' int flags = 0; { QChar c(reinterpret_cast<char*>(&firstBytes)[3]); bool ok; flags = QString(c).toInt(&ok); if (!ok || flags > 8) { ccLog::Error(QString("Invalid file header (4th byte is '%1'?!)").arg(c)); return CC_FERR_WRONG_FILE_TYPE; } } //if (sizeof(PointCoordinateType) == 8 && strncmp((char*)&firstBytes,"CCB3",4) != 0) //{ // QMessageBox::information(0, QString("Wrong version"), QString("This file has been generated with the standard 'float' version!\nAt this time it cannot be read with the 'double' version."),QMessageBox::Ok); // return CC_FERR_WRONG_FILE_TYPE; //} //else if (sizeof(PointCoordinateType) == 4 && strncmp((char*)&firstBytes,"CCB2",4) != 0) //{ // QMessageBox::information(0, QString("Wrong version"), QString("This file has been generated with the new 'double' version!\nAt this time it cannot be read with the standard 'float' version."),QMessageBox::Ok); // return CC_FERR_WRONG_FILE_TYPE; //} if (parameters.alwaysDisplayLoadDialog) { ccProgressDialog pDlg(false, parameters.parentWidget); pDlg.setMethodTitle(QObject::tr("BIN file")); pDlg.setInfo(QObject::tr("Loading: %1").arg(QFileInfo(filename).fileName())); pDlg.setRange(0, 0); pDlg.show(); //concurrent call in a separate thread s_file = ∈ s_container = &container; s_flags = flags; QFuture<CC_FILE_ERROR> future = QtConcurrent::run(_LoadFileV2); while (!future.isFinished()) { #if defined(CC_WINDOWS) ::Sleep(500); #else usleep(500 * 1000); #endif pDlg.setValue(pDlg.value()+1); //pDlg.setValue(static_cast<int>(in.pos())); //DGM: in fact, the file reading part is just half of the work! QApplication::processEvents(); } s_file = 0; s_container = 0; return future.result(); } else { return BinFilter::LoadFileV2(in,container,flags); } } }
void CMatchingDlg::EditPreferences(void) { CEditProjectDlg pDlg(GTK_WINDOW(m_pDlg)); pDlg.Execute(PAGE_MATCHING); }