ccQuadric* ccQuadric::Fit(CCLib::GenericIndexedCloudPersist *cloud, double* rms/*=0*/) { //number of points unsigned count = cloud->size(); if (count < CC_LOCAL_MODEL_MIN_SIZE[HF]) { ccLog::Warning(QString("[ccQuadric::fitTo] Not enough points in input cloud to fit a quadric! (%1 at the very least are required)").arg(CC_LOCAL_MODEL_MIN_SIZE[HF])); return 0; } //project the points on a 2D plane CCVector3 G, X, Y, N; { CCLib::Neighbourhood Yk(cloud); //plane equation const PointCoordinateType* theLSQPlane = Yk.getLSQPlane(); if (!theLSQPlane) { ccLog::Warning("[ccQuadric::Fit] Not enough points to fit a quadric!"); return 0; } assert(Yk.getGravityCenter()); G = *Yk.getGravityCenter(); //local base N = CCVector3(theLSQPlane); assert(Yk.getLSQPlaneX() && Yk.getLSQPlaneY()); X = *Yk.getLSQPlaneX(); //main direction Y = *Yk.getLSQPlaneY(); //secondary direction } //project the points in a temporary cloud ccPointCloud tempCloud("temporary"); if (!tempCloud.reserve(count)) { ccLog::Warning("[ccQuadric::Fit] Not enough memory!"); return 0; } cloud->placeIteratorAtBegining(); for (unsigned k=0; k<count; ++k) { //projection into local 2D plane ref. CCVector3 P = *(cloud->getNextPoint()) - G; tempCloud.addPoint(CCVector3(P.dot(X),P.dot(Y),P.dot(N))); } CCLib::Neighbourhood Zk(&tempCloud); { //set exact values for gravity center and plane equation //(just to be sure and to avoid re-computing them) Zk.setGravityCenter(CCVector3(0,0,0)); PointCoordinateType perfectEq[4] = { 0, 0, 1, 0 }; Zk.setLSQPlane( perfectEq, CCVector3(1,0,0), CCVector3(0,1,0), CCVector3(0,0,1)); } uchar hfdims[3]; const PointCoordinateType* eq = Zk.getHeightFunction(hfdims); if (!eq) { ccLog::Warning("[ccQuadric::Fit] Failed to fit a quadric!"); return 0; } //we recenter the quadric object ccGLMatrix glMat(X,Y,N,G); ccBBox bb = tempCloud.getBB(); CCVector2 minXY(bb.minCorner().x,bb.minCorner().y); CCVector2 maxXY(bb.maxCorner().x,bb.maxCorner().y); ccQuadric* quadric = new ccQuadric(minXY, maxXY, eq, hfdims, &glMat); quadric->setMetaData(QString("Equation"),QVariant(quadric->getEquationString())); //compute rms if necessary if (rms) { const uchar& dX = hfdims[0]; const uchar& dY = hfdims[1]; // const uchar& dZ = hfdims[2]; *rms = 0; for (unsigned k=0; k<count; ++k) { //projection into local 2D plane ref. const CCVector3* P = tempCloud.getPoint(k); PointCoordinateType z = eq[0] + eq[1]*P->u[dX] + eq[2]*P->u[dY] + eq[3]*P->u[dX]*P->u[dX] + eq[4]*P->u[dX]*P->u[dY] + eq[5]*P->u[dY]*P->u[dY]; *rms += (z-P->z)*(z-P->z); } if (count) { *rms = sqrt(*rms / count); quadric->setMetaData(QString("RMS"),QVariant(*rms)); } } return quadric; }
ccBBox ccQuadric::getFitBB(ccGLMatrix& trans) { trans = m_transformation; return ccBBox( CCVector3(m_minCorner.x,m_minCorner.y,m_minZ), CCVector3(m_maxCorner.x,m_maxCorner.y,m_maxZ) ); }
CCVector3 ccUnrollDlg::getAxisPosition() { return CCVector3(static_cast<PointCoordinateType>(doubleSpinBoxAxisX->value()), static_cast<PointCoordinateType>(doubleSpinBoxAxisY->value()), static_cast<PointCoordinateType>(doubleSpinBoxAxisZ->value())); }
void qPCV::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 or one mesh!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } ccHObject* ent = selectedEntities[0]; ccGenericPointCloud* cloud = NULL; ccGenericMesh* mesh = NULL; if (ent->isKindOf(CC_TYPES::POINT_CLOUD)) { cloud = ccHObjectCaster::ToGenericPointCloud(ent); } else if (ent->isKindOf(CC_TYPES::MESH)) { mesh = static_cast<ccGenericMesh*>(ent); cloud = mesh->getAssociatedCloud(); } else { m_app->dispToConsole("Select a point cloud or a mesh!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } if (!cloud->isA(CC_TYPES::POINT_CLOUD)) //TODO { m_app->dispToConsole("Select a real point cloud (or a mesh associated to a real point cloud)!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } ccPointCloud* pc = static_cast<ccPointCloud*>(cloud); ccPcvDlg dlg(m_app->getMainWindow()); //restore previous dialog state if (!s_firstLaunch) { dlg.raysSpinBox->setValue(s_raysSpinBoxValue); dlg.mode180CheckBox->setChecked(s_mode180CheckBoxState); dlg.resSpinBox->setValue(s_resSpinBoxValue); dlg.closedMeshCheckBox->setChecked(s_closedMeshCheckBoxState); } //for meshes only if (!mesh) dlg.closedMeshCheckBox->setEnabled(false); //for using clouds normals as rays std::vector<ccGenericPointCloud*> cloudsWithNormals; ccHObject* root = m_app->dbRootObject(); if (root) { ccHObject::Container clouds; root->filterChildren(clouds,true,CC_TYPES::POINT_CLOUD); for (size_t i=0; i<clouds.size(); ++i) { //we keep only clouds with normals ccGenericPointCloud* cloud = ccHObjectCaster::ToGenericPointCloud(clouds[i]); if (cloud && cloud->hasNormals()) { cloudsWithNormals.push_back(cloud); QString cloudTitle = QString("%1 - %2 points").arg(cloud->getName()).arg(cloud->size()); if (cloud->getParent() && cloud->getParent()->isKindOf(CC_TYPES::MESH)) cloudTitle.append(QString(" (%1)").arg(cloud->getParent()->getName())); dlg.cloudsComboBox->addItem(cloudTitle); } } } if (cloudsWithNormals.empty()) dlg.useCloudRadioButton->setEnabled(false); if (!dlg.exec()) return; //save dialog state { s_firstLaunch = false; s_raysSpinBoxValue = dlg.raysSpinBox->value(); s_mode180CheckBoxState = dlg.mode180CheckBox->isChecked(); s_resSpinBoxValue = dlg.resSpinBox->value(); s_closedMeshCheckBoxState = dlg.closedMeshCheckBox->isChecked(); } //we get the PCV field if it already exists int sfIdx = pc->getScalarFieldIndexByName(CC_PCV_FIELD_LABEL_NAME); //otherwise we create it if (sfIdx < 0) sfIdx = pc->addScalarField(CC_PCV_FIELD_LABEL_NAME); if (sfIdx < 0) { m_app->dispToConsole("Couldn't allocate a new scalar field for computing PCV field ! Try to free some memory ...",ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } pc->setCurrentScalarField(sfIdx); unsigned raysNumber = dlg.raysSpinBox->value(); unsigned res = dlg.resSpinBox->value(); bool meshIsClosed = (mesh ? dlg.closedMeshCheckBox->checkState()==Qt::Checked : false); bool mode360 = !dlg.mode180CheckBox->isChecked(); //progress dialog ccProgressDialog progressCb(true,m_app->getMainWindow()); //PCV type ShadeVis bool success = false; if (!cloudsWithNormals.empty() && dlg.useCloudRadioButton->isChecked()) { //Version with cloud normals as light rays assert(dlg.cloudsComboBox->currentIndex() < (int)cloudsWithNormals.size()); ccGenericPointCloud* pc = cloudsWithNormals[dlg.cloudsComboBox->currentIndex()]; std::vector<CCVector3> rays; unsigned count = pc->size(); rays.resize(count); for (unsigned i=0; i<count; ++i) rays[i] = CCVector3(pc->getPointNormal(i)); success = PCV::Launch(rays,cloud,mesh,meshIsClosed,res,res,&progressCb); } else { //Version with rays sampled on a sphere success = (PCV::Launch(raysNumber,cloud,mesh,meshIsClosed,mode360,res,res,&progressCb) > 0); } if (!success) { pc->deleteScalarField(sfIdx); m_app->dispToConsole("En error occurred during the PCV field computation!",ccMainAppInterface::ERR_CONSOLE_MESSAGE); return; } else { pc->getCurrentInScalarField()->computeMinAndMax(); pc->setCurrentDisplayedScalarField(sfIdx); ccScalarField* sf = static_cast<ccScalarField*>(pc->getScalarField(sfIdx)); if (sf) sf->setColorScale(ccColorScalesManager::GetDefaultScale(ccColorScalesManager::GREY)); ent->showSF(true); ent->showNormals(false); ent->prepareDisplayForRefresh_recursive(); } //currently selected entities parameters may have changed! m_app->updateUI(); //currently selected entities appearance may have changed! m_app->refreshAll(); }
CCLib::SimpleCloud* ccGBLSensor::project(CCLib::GenericCloud* theCloud, int& errorCode, bool autoParameters/*false*/) { assert(theCloud); CCLib::SimpleCloud* newCloud = new CCLib::SimpleCloud(); unsigned pointCount = theCloud->size(); if (!newCloud->reserve(pointCount) || !newCloud->enableScalarField()) //not enough memory { errorCode = -4; delete newCloud; return 0; } ScalarType maxDepth = 0; theCloud->placeIteratorAtBegining(); { for (unsigned i=0; i<pointCount; ++i) { const CCVector3 *P = theCloud->getNextPoint(); CCVector2 Q; ScalarType depth; projectPoint(*P,Q,depth); newCloud->addPoint(CCVector3(Q.x,Q.y,0)); newCloud->setPointScalarValue(i,depth); if (i != 0) maxDepth = std::max(maxDepth,depth); else maxDepth = depth; } } if (autoParameters) { //dimensions = theta, phi, 0 PointCoordinateType bbMin[3],bbMax[3]; newCloud->getBoundingBox(bbMin,bbMax); setTheta(bbMin[0],bbMax[0]); setPhi(bbMin[1],bbMax[1]); setSensorRange(maxDepth); } //clear previous Z-buffer { if (m_depthBuffer.zBuff) delete[] m_depthBuffer.zBuff; m_depthBuffer.zBuff=0; m_depthBuffer.width=0; m_depthBuffer.height=0; } //init new Z-buffer { int width = static_cast<int>(ceil((thetaMax-thetaMin)/deltaTheta)); int height = static_cast<int>(ceil((phiMax-phiMin)/deltaPhi)); if (width*height == 0 || std::max(width,height) > 2048) //too small or... too big! { errorCode = -2; delete newCloud; return 0; } unsigned zBuffSize = width*height; m_depthBuffer.zBuff = new ScalarType[zBuffSize]; if (!m_depthBuffer.zBuff) //not enough memory { errorCode = -4; delete newCloud; return 0; } m_depthBuffer.width = width; m_depthBuffer.height = height; memset(m_depthBuffer.zBuff,0,zBuffSize*sizeof(ScalarType)); } //project points and accumulate them in Z-buffer newCloud->placeIteratorAtBegining(); for (unsigned i=0; i<newCloud->size(); ++i) { const CCVector3 *P = newCloud->getNextPoint(); ScalarType depth = newCloud->getPointScalarValue(i); int x = static_cast<int>(floor((P->x-thetaMin)/deltaTheta)); int y = static_cast<int>(floor((P->y-phiMin)/deltaPhi)); ScalarType& zBuf = m_depthBuffer.zBuff[y*m_depthBuffer.width+x]; zBuf = std::max(zBuf,depth); } errorCode = 0; return newCloud; }
void ccClipBox::drawMeOnly(CC_DRAW_CONTEXT& context) { if (!MACRO_Draw3D(context)) return; if (!m_box.isValid()) return; //m_box.draw(m_selected ? context.bbDefaultCol : ccColor::magenta); m_box.draw(ccColor::yellow); //standard case: list names pushing bool pushName = MACRO_DrawEntityNames(context); if (pushName) glPushName(getUniqueIDForDisplay()); if (m_selected) { //draw the interactors const CCVector3& minC = m_box.minCorner(); const CCVector3& maxC = m_box.maxCorner(); CCVector3 center = m_box.getCenter(); PointCoordinateType scale = computeArrowsScale(); //custom arrow 'context' CC_DRAW_CONTEXT componentContext = context; componentContext.flags &= (~CC_DRAW_ENTITY_NAMES); //we must remove the 'push name flag' so that the arows don't push their own! componentContext._win = 0; //1 if names shall be pushed, 0 otherwise if (pushName) glPushName(0); //fake ID, will be replaced by the arrows one if any DrawUnitArrow(X_MINUS_ARROW*pushName,CCVector3(minC.x,center.y,center.z),CCVector3(-1.0, 0.0, 0.0),scale,ccColor::red,componentContext); DrawUnitArrow(X_PLUS_ARROW*pushName,CCVector3(maxC.x,center.y,center.z),CCVector3( 1.0, 0.0, 0.0),scale,ccColor::red,componentContext); DrawUnitArrow(Y_MINUS_ARROW*pushName,CCVector3(center.x,minC.y,center.z),CCVector3( 0.0,-1.0, 0.0),scale,ccColor::green,componentContext); DrawUnitArrow(Y_PLUS_ARROW*pushName,CCVector3(center.x,maxC.y,center.z),CCVector3( 0.0, 1.0, 0.0),scale,ccColor::green,componentContext); DrawUnitArrow(Z_MINUS_ARROW*pushName,CCVector3(center.x,center.y,minC.z),CCVector3( 0.0, 0.0,-1.0),scale,ccColor::blue,componentContext); DrawUnitArrow(Z_PLUS_ARROW*pushName,CCVector3(center.x,center.y,maxC.z),CCVector3( 0.0, 0.0, 1.0),scale,ccColor::blue,componentContext); DrawUnitCross(CROSS*pushName,minC-CCVector3(scale,scale,scale)/2.0,scale,ccColor::yellow,componentContext); //DrawUnitSphere(SPHERE*pushName,maxC+CCVector3(scale,scale,scale)/2.0,scale/2.0,ccColor::yellow,componentContext); DrawUnitTorus(X_MINUS_TORUS*pushName,CCVector3(minC.x,center.y,center.z),CCVector3(-1.0, 0.0, 0.0),scale,c_lightRed,componentContext); DrawUnitTorus(Y_MINUS_TORUS*pushName,CCVector3(center.x,minC.y,center.z),CCVector3( 0.0,-1.0, 0.0),scale,c_lightGreen,componentContext); DrawUnitTorus(Z_MINUS_TORUS*pushName,CCVector3(center.x,center.y,minC.z),CCVector3( 0.0, 0.0,-1.0),scale,c_lightBlue,componentContext); DrawUnitTorus(X_PLUS_TORUS*pushName,CCVector3(maxC.x,center.y,center.z),CCVector3( 1.0, 0.0, 0.0),scale,c_lightRed,componentContext); DrawUnitTorus(Y_PLUS_TORUS*pushName,CCVector3(center.x,maxC.y,center.z),CCVector3( 0.0, 1.0, 0.0),scale,c_lightGreen,componentContext); DrawUnitTorus(Z_PLUS_TORUS*pushName,CCVector3(center.x,center.y,maxC.z),CCVector3( 0.0, 0.0, 1.0),scale,c_lightBlue,componentContext); if (pushName) glPopName(); } if (pushName) glPopName(); }
PointCoordinateType* ccGBLSensor::projectNormals(CCLib::GenericCloud* aCloud, GenericChunkedArray<3,PointCoordinateType>& theNorms) const { if (!aCloud || !theNorms.isAllocated()) return 0; unsigned size = 3*m_depthBuffer.height*m_depthBuffer.width; if (size == 0) return 0; //depth buffer empty/not initialized! PointCoordinateType* theNewNorms = new PointCoordinateType[size]; if (!theNewNorms) return 0; //not enough memory memset(theNewNorms,0,size*sizeof(PointCoordinateType)); //poject each point+normal { aCloud->placeIteratorAtBegining(); theNorms.placeIteratorAtBegining(); unsigned pointCount = aCloud->size(); for (unsigned i=0;i<pointCount;++i) { const CCVector3* P = aCloud->getNextPoint(); const PointCoordinateType* N = theNorms.getCurrentValue(); CCVector3 U = *P - sensorCenter; U.x += base; CCVector3 S; CCVector2 Q; PointCoordinateType norm = U.norm(); if (norm>ZERO_TOLERANCE) { //normal component along sensor viewing dir. S.z = -CCVector3::vdot(N,U.u)/norm; if (S.z > 1.0-ZERO_TOLERANCE) { S.x = 0; S.y = 0; } else { //project point ScalarType depth1; projectPoint(*P,Q,depth1); //and point+normal CCVector3 R = *P + CCVector3(N); CCVector2 S2; ScalarType depth2; projectPoint(R,S2,depth2); //deduce other normals components PointCoordinateType coef = sqrt((1 - S.z*S.z)/(S.x*S.x + S.y*S.y)); S.x = coef * (S2.x - Q.x); S.y = coef * (S2.y - Q.y); } } else { S = CCVector3(N); } //project in Z-buffer int x = static_cast<int>(floor((Q.x-thetaMin)/deltaTheta)); int y = static_cast<int>(floor((Q.y-phiMin)/deltaPhi)); //on ajoute la normale transformee PointCoordinateType* newN = theNewNorms+3*(y*m_depthBuffer.width+x); CCVector3::vadd(newN,S.u,newN); theNorms.forwardIterator(); } } //normalize { PointCoordinateType* newN = theNewNorms; for (int i=0; i<m_depthBuffer.height*m_depthBuffer.width; ++i,newN+=3) { CCVector3::vnormalize(newN); } } return theNewNorms; }
virtual void add3dFace(const DL_3dFaceData& face) { //TODO: understand what this really is?! CCVector3 P[4]; for (unsigned i=0; i<4; ++i) { P[i] = CCVector3( static_cast<PointCoordinateType>(face.x[i]), static_cast<PointCoordinateType>(face.y[i]), static_cast<PointCoordinateType>(face.z[i]) ); } //create the 'faces' mesh if necessary if (!m_faces) { ccPointCloud* vertices = new ccPointCloud("vertices"); m_faces = new ccMesh(vertices); m_faces->setName("Faces"); m_faces->addChild(vertices); m_faces->setVisible(true); vertices->setEnabled(false); vertices->setLocked(true); m_root->addChild(m_faces); } ccPointCloud* vertices = dynamic_cast<ccPointCloud*>(m_faces->getAssociatedCloud()); if (!vertices) { assert(false); return; } int vertIndexes[4] = {-1, -1, -1, -1}; unsigned addedVertCount = 4; //check if the two last vertices are the same if (P[2].x == P[3].x && P[2].y == P[3].y && P[2].z == P[3].z) addedVertCount = 3; //current face color colorType col[3]; colorType* faceCol = 0; if (getCurrentColour(col)) faceCol = col; //look for already defined vertices unsigned vertCount = vertices->size(); if (vertCount) { //DGM TODO: could we be smarter? for (unsigned i=0; i<addedVertCount; ++i) { for (unsigned j=0; j<vertCount; ++j) { const CCVector3* Pj = vertices->getPoint(j); if (P[i].x == Pj->x && P[i].y == Pj->y && P[i].z == Pj->z) { bool useCurrentVertex = true; //We must also check that the color is the same (if any) if (faceCol || vertices->hasColors()) { const colorType* _faceCol = faceCol ? faceCol : ccColor::white; const colorType* _vertCol = vertices->hasColors() ? vertices->getPointColor(j) : ccColor::white; useCurrentVertex = (_faceCol[0] == _vertCol[0] && _faceCol[1] == _vertCol[1] && _faceCol[2] == _vertCol[2]); } if (useCurrentVertex) { vertIndexes[i] = static_cast<int>(j); break; } } } } } //now create new vertices unsigned createdVertCount = 0; { for (unsigned i=0; i<addedVertCount; ++i) if (vertIndexes[i] < 0) ++createdVertCount; } if (createdVertCount != 0) { //reserve memory for the new vertices if (!vertices->reserve(vertCount+createdVertCount)) { ccLog::Error("[DxfImporter] Not enough memory!"); return; } for (unsigned i=0; i<addedVertCount; ++i) { if (vertIndexes[i] < 0) { vertIndexes[i] = static_cast<int>(vertCount++); vertices->addPoint(P[i]); } } } //number of triangles to add unsigned addTriCount = (addedVertCount == 3 ? 1 : 2); //now add the corresponding face(s) if (!m_faces->reserve(m_faces->size() + addTriCount)) { ccLog::Error("[DxfImporter] Not enough memory!"); return; } m_faces->addTriangle(vertIndexes[0], vertIndexes[1], vertIndexes[2]); if (addedVertCount == 4) m_faces->addTriangle(vertIndexes[0], vertIndexes[2], vertIndexes[3]); //add per-triangle normals { //normals table NormsIndexesTableType* triNormsTable = m_faces->getTriNormsTable(); bool firstTime = false; if (!triNormsTable) { triNormsTable = new NormsIndexesTableType(); m_faces->setTriNormsTable(triNormsTable); m_faces->addChild(triNormsTable); firstTime = true; } //add 1 or 2 new entries unsigned triNormCount = triNormsTable->currentSize(); if (!triNormsTable->reserve(triNormsTable->currentSize() + addTriCount)) { ccLog::Error("[DxfImporter] Not enough memory!"); return; } CCVector3 N = (P[1]-P[0]).cross(P[2]-P[0]); N.normalize(); triNormsTable->addElement(ccNormalVectors::GetNormIndex(N.u)); if (addTriCount == 2) { N = (P[2]-P[0]).cross(P[3]-P[0]); N.normalize(); triNormsTable->addElement(ccNormalVectors::GetNormIndex(N.u)); } //per-triangle normals indexes if (firstTime) { if (!m_faces->reservePerTriangleNormalIndexes()) { ccLog::Error("[DxfImporter] Not enough memory!"); return; } m_faces->showNormals(true); } int n1 = static_cast<int>(triNormCount); m_faces->addTriangleNormalIndexes(n1, n1, n1); if (addTriCount == 2) { int n2 = static_cast<int>(triNormCount+1); m_faces->addTriangleNormalIndexes(n2, n2, n2); } } //and now for the color if (faceCol) { //RGB field already instantiated? if (vertices->hasColors()) { for (unsigned i=0; i<createdVertCount; ++i) vertices->addRGBColor(faceCol); } //otherwise, reserve memory and set all previous points to white by default else if (vertices->setRGBColor(ccColor::white)) { //then replace the last color(s) by the current one for (unsigned i=0; i<createdVertCount; ++i) vertices->setPointColor(vertCount-1-i,faceCol); m_faces->showColors(true); } } else if (vertices->hasColors()) { //add default color if none is defined! for (unsigned i=0; i<createdVertCount; ++i) vertices->addRGBColor(ccColor::white); } }
CC_FILE_ERROR PVFilter::loadFile(const char* filename, ccHObject& container, bool alwaysDisplayLoadDialog/*=true*/, bool* coordinatesShiftEnabled/*=0*/, double* coordinatesShift/*=0*/) { //ccConsole::Print("[PVFilter::loadFile] Opening binary file '%s'...\n",filename); //opening file FILE *fp = fopen(filename, "rb"); if (!fp) return CC_FERR_NO_ERROR; CCLib::CCMiscTools::fseek64(fp,0,2); //we reach the end of the file __int64 fileSize = CCLib::CCMiscTools::ftell64(fp); //file size query CCLib::CCMiscTools::fseek64(fp,0,0); //back to the begining //we read the points number unsigned nbOfPoints = (unsigned) (fileSize / (__int64)(4*sizeof(float))); //ccConsole::Print("[PVFilter::loadFile] Points: %i\n",nbOfPoints); //if the file is too big, it will be chuncked in multiple parts unsigned fileChunkPos = 0; unsigned fileChunkSize = ccMin(nbOfPoints,CC_MAX_NUMBER_OF_POINTS_PER_CLOUD); //new cloud char name[64],k=0; sprintf(name,"unnamed - Cloud #%i",k); ccPointCloud* loadedCloud = new ccPointCloud(name); loadedCloud->reserveThePointsTable(fileChunkSize); loadedCloud->enableScalarField(); float rBuff[3]; //progress dialog ccProgressDialog pdlg(true); //cancel available CCLib::NormalizedProgress nprogress(&pdlg,nbOfPoints); pdlg.setMethodTitle("Open PV file"); char buffer[256]; sprintf(buffer,"Points: %u",nbOfPoints); pdlg.setInfo(buffer); pdlg.start(); //number of points read from the begining of the current cloud part //WARNING: different from lineCounter unsigned pointsRead=0; for (unsigned i=0;i<nbOfPoints;i++) { //if we reach the max. cloud size limit, we cerate a new chunk if (pointsRead == fileChunkPos+fileChunkSize) { loadedCloud->getCurrentInScalarField()->computeMinAndMax(); int sfIdx = loadedCloud->getCurrentInScalarFieldIndex(); loadedCloud->setCurrentDisplayedScalarField(sfIdx); loadedCloud->showSF(sfIdx>=0); container.addChild(loadedCloud); fileChunkPos = pointsRead; fileChunkSize = ccMin(nbOfPoints-pointsRead,CC_MAX_NUMBER_OF_POINTS_PER_CLOUD); sprintf(name,"unnamed - Cloud #%i",++k); loadedCloud = new ccPointCloud(name); loadedCloud->reserveThePointsTable(fileChunkSize); loadedCloud->enableScalarField(); } //we read the 3 coordinates of the point if (fread(rBuff,4,3,fp)>=0) { //conversion to CCVector3 CCVector3 P = CCVector3(PointCoordinateType(rBuff[0]), PointCoordinateType(rBuff[1]), PointCoordinateType(rBuff[2])); loadedCloud->addPoint(P); } else { fclose(fp); return CC_FERR_NO_ERROR; } //then the scalar value if (fread(rBuff,4,1,fp)>=0) { //conversion to DistanceType DistanceType d = DistanceType(rBuff[0]); loadedCloud->setPointScalarValue(pointsRead,d); } else { fclose(fp); return CC_FERR_NO_ERROR; } ++pointsRead; if (!nprogress.oneStep()) { loadedCloud->resize(i+1-fileChunkPos); break; } } loadedCloud->getCurrentInScalarField()->computeMinAndMax(); int sfIdx = loadedCloud->getCurrentInScalarFieldIndex(); loadedCloud->setCurrentDisplayedScalarField(sfIdx); loadedCloud->showSF(sfIdx>=0); container.addChild(loadedCloud); fclose(fp); return CC_FERR_NO_ERROR; }
void cc2DLabel::drawMeOnly3D(CC_DRAW_CONTEXT& context) { assert(!m_points.empty()); //standard case: list names pushing bool pushName = MACRO_DrawEntityNames(context); if (pushName) { //not particularily fast if (MACRO_DrawFastNamesOnly(context)) return; glPushName(getUniqueIDForDisplay()); } const float c_sizeFactor = 4.0f; bool loop = false; size_t count = m_points.size(); switch (count) { case 3: { glPushAttrib(GL_COLOR_BUFFER_BIT); glEnable(GL_BLEND); //we draw the triangle glColor4ub(255,255,0,128); glBegin(GL_TRIANGLES); for (unsigned i=0; i<count; ++i) ccGL::Vertex3v(m_points[i].cloud->getPoint(m_points[i].index)->u); glEnd(); glPopAttrib(); loop=true; } case 2: { //segment width glPushAttrib(GL_LINE_BIT); glLineWidth(c_sizeFactor); //we draw the segments if (isSelected()) glColor3ubv(ccColor::red); else glColor3ubv(ccColor::green); glBegin(GL_LINES); for (unsigned i=0; i<count; i++) { if (i+1<count || loop) { ccGL::Vertex3v(m_points[i].cloud->getPoint(m_points[i].index)->u); ccGL::Vertex3v(m_points[(i+1)%count].cloud->getPoint(m_points[(i+1)%count].index)->u); } } glEnd(); glPopAttrib(); } case 1: { //display point marker as spheres { if (!c_unitPointMarker) { c_unitPointMarker = QSharedPointer<ccSphere>(new ccSphere(1.0f,0,"PointMarker",12)); c_unitPointMarker->showColors(true); c_unitPointMarker->setVisible(true); c_unitPointMarker->setEnabled(true); } //build-up point maker own 'context' CC_DRAW_CONTEXT markerContext = context; markerContext.flags &= (~CC_DRAW_ENTITY_NAMES); //we must remove the 'push name flag' so that the sphere doesn't push its own! markerContext._win = 0; if (isSelected() && !pushName) c_unitPointMarker->setTempColor(ccColor::red); else c_unitPointMarker->setTempColor(ccColor::magenta); for (unsigned i=0; i<count; i++) { glMatrixMode(GL_MODELVIEW); glPushMatrix(); const CCVector3* P = m_points[i].cloud->getPoint(m_points[i].index); ccGL::Translate(P->x,P->y,P->z); glScalef(context.pickedPointsRadius,context.pickedPointsRadius,context.pickedPointsRadius); c_unitPointMarker->draw(markerContext); glPopMatrix(); } } if (m_dispIn3D && !pushName) //no need to display label in point picking mode { QFont font(context._win->getTextDisplayFont()); //takes rendering zoom into account! //font.setPointSize(font.pointSize()+2); font.setBold(true); //draw their name glPushAttrib(GL_DEPTH_BUFFER_BIT); glDisable(GL_DEPTH_TEST); for (unsigned j=0; j<count; j++) { const CCVector3* P = m_points[j].cloud->getPoint(m_points[j].index); QString title = (count == 1 ? getName() : QString("P#%0").arg(m_points[j].index)); context._win->display3DLabel( title, *P + CCVector3( context.pickedPointsTextShift, context.pickedPointsTextShift, context.pickedPointsTextShift), ccColor::magenta, font ); } glPopAttrib(); } } } if (pushName) glPopName(); }
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; }