void tst_QFuture::futureInterface() { { QFuture<void> future; { QFutureInterface<void> i; i.reportStarted(); future = i.future(); i.reportFinished(); } } { QFuture<int> future; { QFutureInterface<int> i; i.reportStarted(); i.reportResult(10); future = i.future(); i.reportFinished(); } QCOMPARE(future.resultAt(0), 10); } { QFuture<int> intFuture; QCOMPARE(intFuture.isStarted(), true); QCOMPARE(intFuture.isFinished(), true); IntResult result; result.reportStarted(); intFuture = result.future(); QCOMPARE(intFuture.isStarted(), true); QCOMPARE(intFuture.isFinished(), false); result.reportFinished(&value); QCOMPARE(intFuture.isStarted(), true); QCOMPARE(intFuture.isFinished(), true); int e = intFuture.result(); QCOMPARE(intFuture.isStarted(), true); QCOMPARE(intFuture.isFinished(), true); QCOMPARE(intFuture.isCanceled(), false); QCOMPARE(e, value); intFuture.waitForFinished(); IntResult intAlgo; intFuture = intAlgo.run(); QFuture<int> intFuture2(intFuture); QCOMPARE(intFuture.result(), value); QCOMPARE(intFuture2.result(), value); intFuture.waitForFinished(); VoidResult a; a.run().waitForFinished(); } }
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 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(); } } }
void qPoissonRecon::doAction() { assert(m_app); if (!m_app) { return; } const ccHObject::Container& selectedEntities = m_app->getSelectedEntities(); //we need one point cloud size_t selNum = selectedEntities.size(); if (selNum != 1) { m_app->dispToConsole("Select only one cloud!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } //a real point cloud ccHObject* ent = selectedEntities[0]; if (!ent->isA(CC_TYPES::POINT_CLOUD)) { m_app->dispToConsole("Select a cloud!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } //with normals! ccPointCloud* pc = static_cast<ccPointCloud*>(ent); if (!pc->hasNormals()) { m_app->dispToConsole("Cloud must have normals!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } bool cloudHasColors = pc->hasColors(); PoissonReconParamDlg prpDlg(m_app->getMainWindow()); prpDlg.importColorsCheckBox->setVisible(cloudHasColors); //init dialog with semi-persistent settings prpDlg.octreeLevelSpinBox->setValue(s_params.depth); prpDlg.weightDoubleSpinBox->setValue(s_params.pointWeight); prpDlg.fullDepthSpinBox->setValue(s_params.fullDepth); prpDlg.samplesPerNodeSpinBox->setValue(s_params.samplesPerNode); prpDlg.densityCheckBox->setChecked(s_params.density); prpDlg.importColorsCheckBox->setChecked(true); if (!prpDlg.exec()) return; //set parameters with dialog settings s_params.depth = prpDlg.octreeLevelSpinBox->value(); s_params.pointWeight = static_cast<float>(prpDlg.weightDoubleSpinBox->value()); s_params.fullDepth = prpDlg.fullDepthSpinBox->value(); s_params.samplesPerNode = static_cast<float>(prpDlg.samplesPerNodeSpinBox->value()); s_params.density = prpDlg.densityCheckBox->isChecked(); bool withColors = pc->hasColors() && prpDlg.importColorsCheckBox->isChecked(); /*** RECONSTRUCTION PROCESS ***/ PoissonMesh mesh; ColoredPoissonMesh coloredMesh; s_cloud = 0; s_mesh = 0; s_coloredMesh = 0; //run in a separate thread bool result = false; { //start message m_app->dispToConsole(QString("[PoissonRecon] Job started (level %1)").arg(s_params.depth),ccMainAppInterface::STD_CONSOLE_MESSAGE); //progress dialog (Qtconcurrent::run can't be canceled!) QProgressDialog pDlg("Initialization", QString(), 0, 0, m_app->getMainWindow()); pDlg.setWindowTitle("Poisson Reconstruction"); pDlg.show(); //QApplication::processEvents(); pDlg.setLabelText(QString("Reconstruction in progress\nlevel: %1 [%2 thread(s)]").arg(s_params.depth).arg(s_params.threads)); QApplication::processEvents(); QFuture<bool> future; //run in a separate thread s_cloud = pc; if (withColors) { s_coloredMesh = &coloredMesh; future = QtConcurrent::run(doReconstructWithColors); } else { s_mesh = &mesh; future = QtConcurrent::run(doReconstruct); } //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(); } result = future.result(); pDlg.hide(); QApplication::processEvents(); } if (result && (!s_mesh || s_mesh->polygonCount() > 0) && (!s_coloredMesh || s_coloredMesh->polygonCount() > 0)) { unsigned nic = 0, noc = 0, nr_faces = 0; if (s_coloredMesh) { s_coloredMesh->resetIterator(); nic = static_cast<unsigned>(s_coloredMesh->inCorePoints.size()); noc = static_cast<unsigned>(s_coloredMesh->outOfCorePointCount()); nr_faces = static_cast<unsigned>(s_coloredMesh->polygonCount()); } else //if (s_mesh) { s_mesh->resetIterator(); nic = static_cast<unsigned>(s_mesh->inCorePoints.size()); noc = static_cast<unsigned>(s_mesh->outOfCorePointCount()); nr_faces = static_cast<unsigned>(s_mesh->polygonCount()); } unsigned nr_vertices = nic+noc; //end message m_app->dispToConsole(QString("[PoissonRecon] Job finished (%1 triangles, %2 vertices)").arg(nr_faces).arg(nr_vertices),ccMainAppInterface::STD_CONSOLE_MESSAGE); ccPointCloud* newPC = new ccPointCloud("vertices"); ccMesh* newMesh = new ccMesh(newPC); newMesh->addChild(newPC); if (newPC->reserve(nr_vertices) && newMesh->reserve(nr_faces)) { ccScalarField* densitySF = 0; if (s_params.density) { densitySF = new ccScalarField("Density"); if (!densitySF->reserve(nr_vertices)) { m_app->dispToConsole(QString("[PoissonRecon] Failed to allocate memory for storing density!"),ccMainAppInterface::WRN_CONSOLE_MESSAGE); densitySF->release(); densitySF = 0; } } if (s_coloredMesh) { bool importColors = newPC->reserveTheRGBTable(); if (!importColors) { if (m_app) m_app->dispToConsole("Not enough memory to import colors!", ccMainAppInterface::ERR_CONSOLE_MESSAGE); } //add 'in core' points { for (unsigned i=0; i<nic; i++) { ColoredVertex& p = s_coloredMesh->inCorePoints[i]; CCVector3 p2( static_cast<PointCoordinateType>(p.point.coords[0]), static_cast<PointCoordinateType>(p.point.coords[1]), static_cast<PointCoordinateType>(p.point.coords[2]) ); newPC->addPoint(p2); if (importColors) { newPC->addRGBColor(p.color); } if (densitySF) { ScalarType sf = static_cast<ScalarType>(p.value); densitySF->addElement(sf); } } } //add 'out of core' points { for (unsigned i=0; i<noc; i++) { ColoredVertex p; s_coloredMesh->nextOutOfCorePoint(p); CCVector3 p2( static_cast<PointCoordinateType>(p.point.coords[0]), static_cast<PointCoordinateType>(p.point.coords[1]), static_cast<PointCoordinateType>(p.point.coords[2]) ); newPC->addPoint(p2); if (importColors) { newPC->addRGBColor(p.color); } if (densitySF) { ScalarType sf = static_cast<ScalarType>(p.value); densitySF->addElement(sf); } } } newPC->showColors(importColors); } else { //add 'in core' points { for (unsigned i=0; i<nic; i++) { Vertex& p = s_mesh->inCorePoints[i]; CCVector3 p2( static_cast<PointCoordinateType>(p.point.coords[0]), static_cast<PointCoordinateType>(p.point.coords[1]), static_cast<PointCoordinateType>(p.point.coords[2]) ); newPC->addPoint(p2); if (densitySF) { ScalarType sf = static_cast<ScalarType>(p.value); densitySF->addElement(sf); } } } //add 'out of core' points { for (unsigned i=0; i<noc; i++) { Vertex p; s_mesh->nextOutOfCorePoint(p); CCVector3 p2( static_cast<PointCoordinateType>(p.point.coords[0]), static_cast<PointCoordinateType>(p.point.coords[1]), static_cast<PointCoordinateType>(p.point.coords[2]) ); newPC->addPoint(p2); if (densitySF) { ScalarType sf = static_cast<ScalarType>(p.value); densitySF->addElement(sf); } } } newPC->showColors(false); } // density SF if (densitySF) { densitySF->computeMinAndMax(); densitySF->showNaNValuesInGrey(false); int sfIdx = newPC->addScalarField(densitySF); newPC->setCurrentDisplayedScalarField(sfIdx); newPC->showSF(true); newMesh->showColors(newPC->colorsShown()); newMesh->showSF(true); } //add faces { for (unsigned i=0; i<nr_faces; i++) { std::vector<CoredVertexIndex> triangleIndexes; if (s_mesh) s_mesh->nextPolygon(triangleIndexes); else s_coloredMesh->nextPolygon(triangleIndexes); if (triangleIndexes.size() == 3) { for (std::vector<CoredVertexIndex>::iterator it = triangleIndexes.begin(); it != triangleIndexes.end(); ++it) if (!it->inCore) it->idx += nic; newMesh->addTriangle( triangleIndexes[0].idx, triangleIndexes[1].idx, triangleIndexes[2].idx ); } else { //Can't handle anything else than triangles yet! assert(false); } } } newMesh->setName(QString("Mesh[%1] (level %2)").arg(pc->getName()).arg(s_params.depth)); newPC->setEnabled(false); newMesh->setVisible(true); newMesh->computeNormals(true); newMesh->showColors(newMesh->hasColors()); //copy Global Shift & Scale information newPC->setGlobalShift(pc->getGlobalShift()); newPC->setGlobalScale(pc->getGlobalScale()); //output mesh m_app->addToDB(newMesh); } else { delete newMesh; newMesh = 0; m_app->dispToConsole("Not enough memory!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); } //currently selected entities parameters may have changed! m_app->updateUI(); //currently selected entities appearance may have changed! m_app->refreshAll(); } else { m_app->dispToConsole("Reconstruction failed!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); } s_cloud = 0; s_mesh = 0; s_coloredMesh = 0; }
//------------------------------------------------------------------------------------------- Kst::Object::UpdateType AsciiSource::internalDataSourceUpdate(bool read_completely) { //MeasureTime t("AsciiSource::internalDataSourceUpdate: " + _filename); if (_busy) return NoChange; // forget about cached data _fileBuffer.clear(); if (!_haveHeader) { _haveHeader = initRowIndex(); if (!_haveHeader) { return NoChange; } } updateLists(); QFile file(_filename); if (!AsciiFileBuffer::openFile(file)) { // Qt: If the device is closed, the size returned will not reflect the actual size of the device. return NoChange; } if (_updatesDisabled) { _fileSize = 0; } else { _fileSize = file.size(); } bool force_update = true; if (_fileSize == file.size()) { force_update = false; } _fileCreationTime_t = QFileInfo(file).created().toTime_t(); int col_count = _fieldList.size() - 1; // minus INDEX bool new_data = false; // emit progress message if there are more than 100 MB to parse if (_fileSize - _lastFileSize > 100 * 1024 * 1024 && read_completely) { _showFieldProgress = true; emitProgress(1, tr("Parsing '%1' ...").arg(_filename)); QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); QFuture<bool> future = QtConcurrent::run(&_reader, &AsciiDataReader::findAllDataRows, read_completely, &file, _fileSize, col_count); _busy = true; while (_busy) { if (future.isFinished()) { try { new_data = future; } catch ( const std::exception&) { // TODO out of memory? } _busy = false; emitProgress(50, tr("Finished parsing '%1'").arg(_filename)); } else { ms::sleep(500); emitProgress(1 + 99.0 * _reader.progressValue() / 100.0, tr("Parsing '%1': %2 rows").arg(_filename).arg(QString::number(_reader.progressRows()))); QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } } } else { _showFieldProgress = false; new_data = _reader.findAllDataRows(read_completely, &file, _fileSize, col_count); } _lastFileSize = _fileSize; return (!new_data && !force_update ? NoChange : Updated); }
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(); }
bool generateImagesAndXML() { QString baseDestDir=mInfo->destUrl().toLocalFile(); if (!createDir(baseDestDir)) return false; mXMLFileName=baseDestDir + "/gallery.xml"; XMLWriter xmlWriter; if (!xmlWriter.open(mXMLFileName)) { logError(i18n("Could not create gallery.xml")); return false; } XMLElement collectionsX(xmlWriter, "collections"); // Loop on collections QList<ImageCollection>::ConstIterator collectionIt=mInfo->mCollectionList.constBegin(); QList<ImageCollection>::ConstIterator collectionEnd=mInfo->mCollectionList.constEnd(); for (; collectionIt!=collectionEnd; ++collectionIt) { ImageCollection collection=*collectionIt; QString collectionFileName = webifyFileName(collection.name()); QString destDir = baseDestDir + '/' + collectionFileName; if (!createDir(destDir)) return false; XMLElement collectionX(xmlWriter, "collection"); xmlWriter.writeElement("name", collection.name()); xmlWriter.writeElement("fileName", collectionFileName); xmlWriter.writeElement("comment", collection.comment()); // Gather image element list KUrl::List imageList = collection.images(); RemoteUrlHash remoteUrlHash; if (!downloadRemoteUrls(collection.name(), imageList, &remoteUrlHash)) { return false; } QList<ImageElement> imageElementList; Q_FOREACH(const KUrl& url, imageList) { const QString path = remoteUrlHash.value(url, url.toLocalFile()); if (path.isEmpty()) { continue; } KPImageInfo info(url); ImageElement element = ImageElement(info); element.mPath = remoteUrlHash.value(url, url.toLocalFile()); imageElementList << element; } // Generate images logInfo( i18n("Generating files for \"%1\"", collection.name()) ); ImageGenerationFunctor functor(that, mInfo, destDir); QFuture<void> future = QtConcurrent::map(imageElementList, functor); QFutureWatcher<void> watcher; watcher.setFuture(future); connect(&watcher, SIGNAL(progressValueChanged(int)), mProgressDialog->progressWidget(), SLOT(setProgress(int))); mProgressDialog->progressWidget()->setTotal(imageElementList.count()); while (!future.isFinished()) { qApp->processEvents(); if (mProgressDialog->isHidden()) { future.cancel(); future.waitForFinished(); return false; } } // Generate xml Q_FOREACH(const ImageElement& element, imageElementList) { element.appendToXML(xmlWriter, mInfo->copyOriginalImage()); } }
int qPoissonReconPlugin::doAction(ccHObject::Container& selectedEntities, unsigned& uiModificationFlags, ccProgressDialog* progressCb/*=NULL*/, QWidget* parent/*=NULL*/) { //we need one point cloud unsigned selNum = selectedEntities.size(); if (selNum!=1) return -1; //a real point cloud ccHObject* ent = selectedEntities[0]; if (!ent->isA(CC_POINT_CLOUD)) return -1; //with normals! ccPointCloud* pc = static_cast<ccPointCloud*>(ent); if (!pc->hasNormals()) return -2; bool ok; #if (QT_VERSION >= QT_VERSION_CHECK(4, 5, 0)) int depth = QInputDialog::getInt(0, "Poisson reconstruction","Octree depth:", 8, 1, 24, 1, &ok); #else int depth = QInputDialog::getInteger(0, "Poisson reconstruction","Octree depth:", 8, 1, 24, 1, &ok); #endif if (!ok) return 1; //TODO: faster, lighter unsigned i,count = pc->size(); float* points = new float[count*3]; if (!points) return -3; float* normals = new float[count*3]; if (!normals) { delete[] points; return -3; } float* _points = points; float* _normals = normals; for (i=0;i<count;++i) { const CCVector3* P = pc->getPoint(i); *_points++ = (float)P->x; *_points++ = (float)P->y; *_points++ = (float)P->z; const PointCoordinateType* N = pc->getPointNormal(i); *_normals++ = (float)N[0]; *_normals++ = (float)N[1]; *_normals++ = (float)N[2]; } /*** RECONSTRUCTION PROCESS ***/ CoredVectorMeshData mesh; PoissonReconLib::PoissonReconResultInfo info; bool result = false; if (progressCb) { progressCb->setCancelButton(0); progressCb->setRange(0,0); progressCb->setInfo("Operation in progress"); progressCb->setMethodTitle("Poisson Reconstruction"); progressCb->start(); //QApplication::processEvents(); //run in a separate thread s_points = points; s_normals = normals; s_count = count; s_depth = depth; s_mesh = &mesh; s_info = &info; QFuture<void> future = QtConcurrent::run(doReconstruct); unsigned progress = 0; while (!future.isFinished()) { #if defined(_WIN32) || defined(WIN32) ::Sleep(500); #else sleep(500); #endif progressCb->update(++progress); //Qtconcurrent::run can't be canceled! /*if (progressCb->isCancelRequested()) { future.cancel(); future.waitForFinished(); s_result = false; break; } //*/ } result = s_result; progressCb->stop(); QApplication::processEvents(); } else { result = PoissonReconLib::reconstruct(count, points, normals, mesh, depth, &info); } delete[] points; points=0; delete[] normals; normals=0; if (!result || mesh.polygonCount() < 1) return -4; unsigned nic = (unsigned)mesh.inCorePoints.size(); unsigned noc = (unsigned)mesh.outOfCorePointCount(); unsigned nr_vertices = nic+noc; unsigned nr_faces = (unsigned)mesh.polygonCount(); ccPointCloud* newPC = new ccPointCloud("vertices"); newPC->reserve(nr_vertices); //we enlarge bounding box a little bit (2%) PointCoordinateType bbMin[3],bbMax[3]; pc->getBoundingBox(bbMin,bbMax); CCVector3 boxHalfDiag = (CCVector3(bbMax)-CCVector3(bbMin))*0.51f; CCVector3 boxCenter = (CCVector3(bbMax)+CCVector3(bbMin))*0.5f; CCVector3 filterMin = boxCenter-boxHalfDiag; CCVector3 filterMax = boxCenter+boxHalfDiag; Point3D<float> p; CCVector3 p2; for (i=0; i<nic; i++) { p = mesh.inCorePoints[i]; p2.x = p.coords[0]*info.scale+info.center[0]; p2.y = p.coords[1]*info.scale+info.center[1]; p2.z = p.coords[2]*info.scale+info.center[2]; newPC->addPoint(p2); } for (i=0; i<noc; i++) { mesh.nextOutOfCorePoint(p); p2.x = p.coords[0]*info.scale+info.center[0]; p2.y = p.coords[1]*info.scale+info.center[1]; p2.z = p.coords[2]*info.scale+info.center[2]; newPC->addPoint(p2); } ccMesh* newMesh = new ccMesh(newPC); newMesh->setName(QString("Mesh[%1] (level %2)").arg(pc->getName()).arg(depth)); newMesh->reserve(nr_faces); newMesh->addChild(newPC); std::vector<CoredVertexIndex> vertices; for (i=0; i < nr_faces; i++) { mesh.nextPolygon(vertices); if (vertices.size()!=3) { //Can't handle anything else than triangles yet! assert(false); } else { for (std::vector<CoredVertexIndex>::iterator it = vertices.begin(); it != vertices.end(); ++it) if (!it->inCore) it->idx += nic; newMesh->addTriangle(vertices[0].idx, vertices[1].idx, vertices[2].idx); } } newPC->setVisible(false); newMesh->setVisible(true); newMesh->computeNormals(); //output mesh selectedEntities.push_back(newMesh); //currently selected entities parameters may have changed! uiModificationFlags |= CC_PLUGIN_REFRESH_ENTITY_BROWSER; //currently selected entities appearance may have changed! uiModificationFlags |= CC_PLUGIN_REFRESH_GL_WINDOWS; return 1; }