#include "edit_scan.h" #include "wrap/gui/trackball.h" #include "wrap/qt/trackball.h" //QT2VCG trackball function #include "wrap/qt/to_string.h" //QT2VCG trackball function #include #define EDITSCANHACK #ifdef EDITSCANHACK #include struct Sample{ Point3f p,n,v; Sample(Point3f p, Point3f n, Point3f v){ this->p = p; this->n = n; this->v = v; } }; vector samples; void write_to_ply(){ FILE* fid = fopen( "/tmp/output.ply", "w" ); if( fid == NULL ){ qDebug("The output cannot be opened!"); return; } fprintf(fid, "ply\n"); fprintf(fid, "format ascii 1.0\n"); fprintf(fid, "element vertex %d\n", samples.size() ); fprintf(fid, "property float x\n"); fprintf(fid, "property float y\n"); fprintf(fid, "property float z\n"); fprintf(fid, "property float nx\n"); fprintf(fid, "property float ny\n"); fprintf(fid, "property float nz\n"); fprintf(fid, "property float vx\n"); fprintf(fid, "property float vy\n"); fprintf(fid, "property float vz\n"); fprintf(fid, "end_header\n"); for(int i=0; imd = &md; this->gla = gla; gla->fov = 5; // Orthographic isScanning = false; // Trigger is off initially timer = 0; //--- Create a new model to store the scan cloud cloud = md.addNewMesh("Scan cloud",false); //--- Instantiate the UI, and connect events widget = new Widget(gla->window()); connect(widget, SIGNAL(laser_parameter_updated()), this, SLOT(laser_parameter_updated())); connect(widget, SIGNAL(scan_requested()), this, SLOT(scan_requested())); connect(widget, SIGNAL(save_requested()), this, SLOT(save_requested())); //--- Compute initial beam laser_parameter_updated(); return true; } // We need to refresh the laser scan completely! void VirtualScan::laser_parameter_updated(){ //--- Retrieve values from GUI int period = 1000 / widget->getSampfreq(); int numsamp = widget->getNumsample(); // Compute start and stop coordinates in image space Point2f delta( widget->getScanwidth()*gla->height()/(3.0*100.0), 0 ); Point2f str( gla->width()/2, gla->height()/2 ); str-=delta; Point2f sto( gla->width()/2, gla->height()/2 ); sto+=delta; // float width = *md->mm()->cm.bbox.MaxDim()/100.0; qDebug("period: %d, samples: %d", period, numsamp); // qDebug() << toString(str) << " " << toString(sto); //--- Create the geometry of the scanline gla->update(); // since we use gluproject sline = ScanLine( numsamp, str, sto); // sline = ScanLineGeom( 10, .1 ); // hardcoded parameters (GUI independent) //--- Create a timer which enables scanning periodically if( timer!=0 ) delete timer; timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(readytoscan())); timer->start(period); // period of repetition in ms //--- Update the laser rendering gla->update(); } void VirtualScan::EndEdit(MeshModel&, GLArea* ){ delete cloud; delete widget; } void VirtualScan::save_requested(){ #ifdef EDITSCANHACK //--- Output model of "samples" to Ply file qDebug("Writing to ply..."); write_to_ply(); #else //--- Create a new model to store the scan cloud cloud = md->addNewMesh("Scan cloud",false); #endif } // This is called only when mouse is pressed at first during a drag or a click is received void VirtualScan::mousePressEvent(QMouseEvent* e, MeshModel &, GLArea* gla){ this->laser_parameter_updated(); gla->trackball.MouseDown(e->x(),gla->height()-e->y(), QT2VCG(e->button(), e->modifiers() ) ); gla->update(); } // This is called during the whole drag void VirtualScan::mouseMoveEvent(QMouseEvent* e, MeshModel &, GLArea* gla){ gla->trackball.MouseMove(e->x(),gla->height()-e->y()); gla->update(); } void VirtualScan::mouseReleaseEvent(QMouseEvent* e, MeshModel &, GLArea* gla){ isScanning = false; gla->trackball.MouseUp(e->x(),gla->height()-e->y(), QT2VCG(e->button(), e->modifiers() ) ); gla->update(); } void VirtualScan::Decorate(MeshModel& mm, GLArea* gla){ // Scan the mesh only if we are triggering a scan and if the scanner is ready to suck in a new sample // This needs to be done after the mesh rendering has been done, but before any the scanned cloud is drawn!! if( isScanning && sampleReady ){ sampleReady = false; isScanning = false; scanpoints(); } //--- Draw the scanned samples stored in the cloud glDisable(GL_LIGHTING); cloud->cm.C() = Color4b(255,200,200,255); glColor4f(.4f,.4f,1.f,.6f); cloud->glw.cdm = GLW::DMPoints; cloud->glw.SetHintParamf(GLW::HNPPointSize,SCANPOINTSIZE); cloud->Render(GLW::DMPoints, GLW::CMPerMesh, GLW::TMNone); glEnable(GL_LIGHTING); if(widget->getDrawLineFlag()){ //--- Shows the view directions of the scanned samples // The "decorate plugin does nothing inside GLW, but does it directly // put these before ->Render // cloud->updateDataMask(MeshModel::MM_VERTNORMAL); // cloud->glw.cnm = GLW::NMPerVert; float LineLen = mm.cm.bbox.Diag()/20.0; glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_LIGHTING); glBegin(GL_LINES); glColor4f(.4f,.4f,1.f,.6f); for(CMeshO::VertexIterator vi=cloud->cm.vert.begin(); vi!=cloud->cm.vert.end(); ++vi){ glVertex((*vi).P()); glVertex((*vi).P()+(*vi).N()*LineLen); } glEnd(); } //--- Draw the laser beam (just to help interfacing) sline.render(gla); } ScanLine::ScanLine(int N, Point2f& srt, Point2f& end ){ float delta = 1.0 / (N-1); // qDebug() << "Scanpoint list: "; #define RANGE #ifdef LASER float alpha=0; for( int i=0; i NewSelFace; GLPickTri::PickFaceVisible(curr[0], curr[1], this->md->mm()->cm, NewSelFace, 2, 2); vector::iterator fpi; /* //For debug: select face where the scanner went through (so * that we can see it on the screen) for(fpi=NewSelFace.begin();fpi!=NewSelFace.end();++fpi) (*fpi)->SetS();*/ // Get face normal int normCaught = 0; Point3f normal(0.0, 0.0, 0.0); for(fpi=NewSelFace.begin();fpi!=NewSelFace.end();++fpi){ CMeshO::FaceType::NormalType n; n = (*fpi)->N(); normal = Point3f(n[0], n[1], n[2]); normCaught = 1; // Use first face and exit break; //cout << n[0] << " " << n[1] << " " << n[2] << endl; } // Print warning if no face was found for scanned point (means // normal will be undefined) if (!normCaught){ cout << "Could not find a face for scanned point.. skipping" << endl; continue; } //--- Retrieve x,y coordinates in object space and another sample // with a bit of offset toward the camera Point3f sample = myGluUnProject( curr, z ); Point3f sample2 = myGluUnProject( curr, z+.01); Point3f viewdir = (sample-sample2).normalized(); // qDebug() << "correspodning in object space to: " << toString(sample); //--- Reject samples which view-dir is too far from camera if( viewdir.dot(normal) < min_th_rad ){ qDebug() << "rejected!!!"; continue; } //--- Add scanned sample to the cloud tri::Allocator::AddVertices(cloud->cm,1); cloud->cm.vert.back().P() = sample; cloud->cm.vert.back().N() = viewdir; #ifdef EDITSCANHACK // TODO: How compute normal from depth buffer? samples.push_back(Sample(sample,normal,viewdir)); #endif } delete [] buffer; } void ScanLine::render(GLArea* gla){ #if 0 //--- DEBUG! why mv[4,3] = -1000? GLdouble mv[16]; glGetDoublev(GL_MODELVIEW_MATRIX, mv); for(int i=0; i<4; i++) qDebug() << mv[4*i+0] << " " << mv[4*i+1] << " " << mv[4*i+2] << " " << mv[4*i+3]; qDebug(); #endif // This draws directly in 2D image space glDisable(GL_DEPTH_TEST); glPointSize(SCANPOINTSIZE); glColor(Color4f(255,0,0,255)); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0, gla->width(), 0, gla->height(), -1, 1); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glColor3f(1.0,0.0,0.0); glBegin(GL_POINTS); for(int i=0; iwidth()/2, gla->height()/2 ); glEnd(); // glRectf(100,100, 200, 200); glPopMatrix(); // restore modelview // The pop must be done in the projection mode glMatrixMode(GL_PROJECTION); glPopMatrix(); } // Must be at the end of everything in CPP file or get segfault at plugin load Q_EXPORT_PLUGIN(VirtualScan)