diff --git a/src/meshlab/glarea.cpp b/src/meshlab/glarea.cpp index 38b8df231..f1eb5da11 100644 --- a/src/meshlab/glarea.cpp +++ b/src/meshlab/glarea.cpp @@ -365,6 +365,11 @@ void GLArea::paintGL() if(error) { log->Logf(GLLogStream::WARNING,"There are gl errors"); } + + //check if viewers are linked + MainWindow *window = (MainWindow*) QApplication::activeWindow(); + if(window && window->linkViewersAct->isChecked()) + mvc->updateTrackballInViewers(); } void GLArea::displayInfo() @@ -652,18 +657,20 @@ void GLArea::mousePressEvent(QMouseEvent*e) void GLArea::mouseMoveEvent(QMouseEvent*e) { - if( (iEdit && !suspendedEditor) ) - iEdit->mouseMoveEvent(e,*mm(),this); - else { - if (isDefaultTrackBall()) - { - trackball.MouseMove(e->x(),height()-e->y()); - setCursorTrack(trackball.current_mode); - } - else trackball_light.MouseMove(e->x(),height()-e->y()); - update(); - } + if( (iEdit && !suspendedEditor) ) + iEdit->mouseMoveEvent(e,*mm(),this); + else { + if (isDefaultTrackBall()) + { + trackball.MouseMove(e->x(),height()-e->y()); + setCursorTrack(trackball.current_mode); + } + else trackball_light.MouseMove(e->x(),height()-e->y()); + update(); + } + } + // When mouse is released we set the correct mouse cursor void GLArea::mouseReleaseEvent(QMouseEvent*e) { @@ -896,6 +903,7 @@ void GLArea::setView() // HOW LARGE IS THE TRACKBALL ICON ON THE SCREEN. float viewRatio = 1.75f; float cameraDist = viewRatio / tanf(vcg::math::ToRad(fov*.5f)); + if(fov==5) cameraDist = 1000; // small hack for orthographic projection where camera distance is rather meaningless... nearPlane = cameraDist - 2.f*clipRatioNear; @@ -1055,3 +1063,434 @@ void GLArea::updateLayerSetVisibility(int meshId, bool visibility) { visibilityMap.insert(meshId,visibility); } + +// --------------- Methods involving shots ------------------------------------- + +float GLArea::getCameraDistance() +{ + // This parameter is the one that controls: + // HOW LARGE IS THE TRACKBALL ICON ON THE SCREEN. + float viewRatio = 1.75f; + float cameraDist = viewRatio / tanf(vcg::math::ToRad(fov*.5f)); + + return cameraDist; +} + +void GLArea::initializeShot(Shot &shot) +{ + //Da vedere + shot.Intrinsics.PixelSizeMm[0]=0.036916077; + shot.Intrinsics.PixelSizeMm[1]=0.036916077; + + shot.Intrinsics.DistorCenterPx[0]=width()/2; + shot.Intrinsics.DistorCenterPx[1]=height()/2; + shot.Intrinsics.CenterPx[0]=width()/2; + shot.Intrinsics.CenterPx[1]=height()/2; + shot.Intrinsics.ViewportPx[0]=width(); + shot.Intrinsics.ViewportPx[1]=height(); + + double viewportYMm = shot.Intrinsics.PixelSizeMm[1]*shot.Intrinsics.ViewportPx[1]; + float defaultFov=60.0; + shot.Intrinsics.FocalMm = viewportYMm/(2*tanf(vcg::math::ToRad(defaultFov/2))); //27.846098mm + + shot.Extrinsics.SetIdentity(); +} + +bool GLArea::viewFromFile() +{ + Shot shot; + + QString filename = QFileDialog::getOpenFileName(this, tr("Load Project"), "./", tr("Xml Files (*.xml)")); + + QFile qf(filename); + QFileInfo qfInfo(filename); + + if( !qf.open(QIODevice::ReadOnly ) ) + return false; + + QString project_path = qfInfo.absoluteFilePath(); + + QDomDocument doc("XmlDocument"); //It represents the XML document + if(!doc.setContent( &qf )) + return false; + + QString type = doc.doctype().name(); + + //TextAlign file project + if(type == "RegProjectML") + loadShotFromTextAlignFile(shot, doc); + //View State file + else if(type == "ViewState") + loadViewFromViewStateFile(shot, doc); + + qDebug("End file reading"); + qf.close(); + + return true; +} + +void GLArea::loadShotFromTextAlignFile(Shot &shot, QDomDocument &doc) +{ + QDomElement root = doc.documentElement(); + QDomNode node; + + node = root.firstChild(); + + //Devices + while(!node.isNull()){ + if(QString::compare(node.nodeName(),"Device")==0) + { + QString type = node.attributes().namedItem("type").nodeValue(); + if (type== "GlImageWidget") + { + //Aligned Image + if(QString::compare(node.attributes().namedItem("aligned").nodeValue(),"1")==0){ + QDomNode nodeb = node.firstChild(); + QDomNamedNodeMap attr = nodeb.attributes(); + vcg::Point3d tra; + tra[0] = attr.namedItem("SimTra").nodeValue().section(' ',0,0).toDouble(); + tra[1] = attr.namedItem("SimTra").nodeValue().section(' ',1,1).toDouble(); + tra[2] = attr.namedItem("SimTra").nodeValue().section(' ',2,2).toDouble(); + shot.Extrinsics.SetTra(-tra); + + vcg::Matrix44d rot; + QStringList values = attr.namedItem("SimRot").nodeValue().split(" ", QString::SkipEmptyParts); + for(int y = 0; y < 4; y++) + for(int x = 0; x < 4; x++) + rot[y][x] = values[x + 4*y].toDouble(); + shot.Extrinsics.SetRot(rot); + + vcg::Camera &cam = shot.Intrinsics; + cam.FocalMm = attr.namedItem("Focal").nodeValue().toDouble(); + cam.ViewportPx.X() = attr.namedItem("Viewport").nodeValue().section(' ',0,0).toInt(); + cam.ViewportPx.Y() = attr.namedItem("Viewport").nodeValue().section(' ',1,1).toInt(); + cam.CenterPx[0] = attr.namedItem("Center").nodeValue().section(' ',0,0).toInt(); + cam.CenterPx[1] = attr.namedItem("Center").nodeValue().section(' ',1,1).toInt(); + cam.PixelSizeMm[0] = attr.namedItem("ScaleF").nodeValue().section(' ',0,0).toDouble(); + cam.PixelSizeMm[1] = attr.namedItem("ScaleF").nodeValue().section(' ',1,1).toDouble(); + cam.k[0] = attr.namedItem("LensDist").nodeValue().section(' ',0,0).toDouble(); + cam.k[1] = attr.namedItem("LensDist").nodeValue().section(' ',1,1).toDouble(); + + // scale correction + float scorr = attr.namedItem("ScaleCorr").nodeValue().toDouble(); + if(scorr != 0.0) { + cam.PixelSizeMm[0] *= scorr; + cam.PixelSizeMm[1] *= scorr; + } + + } + } + } + node = node.nextSibling(); + } + + //Adjust params for Meshlab settings + + //resize viewport + int w = shot.Intrinsics.ViewportPx[0]; + int h = shot.Intrinsics.ViewportPx[1]; + + shot.Intrinsics.DistorCenterPx[0]=w/2; + shot.Intrinsics.DistorCenterPx[1]=h/2; + shot.Intrinsics.CenterPx[0]=w/2; + shot.Intrinsics.CenterPx[1]=h/2; + shot.Intrinsics.ViewportPx[0]=w; + shot.Intrinsics.ViewportPx[1]=h; + + //Compute new scale + double viewportYMm=shot.Intrinsics.PixelSizeMm[1]*shot.Intrinsics.ViewportPx[1]; + fov = 2*(vcg::math::ToDeg(atanf(viewportYMm/(2*shot.Intrinsics.FocalMm)))); + + float cameraDist = getCameraDistance(); + + Matrix44f rotFrom; + shot.Extrinsics.Rot().ToMatrix(rotFrom); + + Point3f p1 = rotFrom*(vcg::Point3f::Construct(shot.Extrinsics.Tra())); + + Point3f p2 = (Point3f(0,0,cameraDist)); + + trackball.track.sca =abs(p2.Z()/p1.Z()); + + loadShot(QPair (shot,trackball.track.sca)); + +} + +void GLArea::loadViewFromViewStateFile(Shot &shot, QDomDocument &doc) +{ + + QDomElement root = doc.documentElement(); + QDomNode node = root.firstChild(); + + while(!node.isNull()){ + if(QString::compare(node.nodeName(),"CamParam")==0) + { + QDomNamedNodeMap attr = node.attributes(); + vcg::Point3d tra; + tra[0] = attr.namedItem("SimTra").nodeValue().section(' ',0,0).toDouble(); + tra[1] = attr.namedItem("SimTra").nodeValue().section(' ',1,1).toDouble(); + tra[2] = attr.namedItem("SimTra").nodeValue().section(' ',2,2).toDouble(); + shot.Extrinsics.SetTra(-tra); + + vcg::Matrix44d rot; + QStringList values = attr.namedItem("SimRot").nodeValue().split(" ", QString::SkipEmptyParts); + for(int y = 0; y < 4; y++) + for(int x = 0; x < 4; x++) + rot[y][x] = values[x + 4*y].toDouble(); + shot.Extrinsics.SetRot(rot); + + vcg::Camera &cam = shot.Intrinsics; + cam.FocalMm = attr.namedItem("Focal").nodeValue().toDouble(); + cam.ViewportPx.X() = attr.namedItem("Viewport").nodeValue().section(' ',0,0).toInt(); + cam.ViewportPx.Y() = attr.namedItem("Viewport").nodeValue().section(' ',1,1).toInt(); + cam.CenterPx[0] = attr.namedItem("Center").nodeValue().section(' ',0,0).toInt(); + cam.CenterPx[1] = attr.namedItem("Center").nodeValue().section(' ',1,1).toInt(); + cam.PixelSizeMm[0] = attr.namedItem("ScaleF").nodeValue().section(' ',0,0).toDouble(); + cam.PixelSizeMm[1] = attr.namedItem("ScaleF").nodeValue().section(' ',1,1).toDouble(); + cam.k[0] = attr.namedItem("LensDist").nodeValue().section(' ',0,0).toDouble(); + cam.k[1] = attr.namedItem("LensDist").nodeValue().section(' ',1,1).toDouble(); + + // scale correction + float scorr = attr.namedItem("ScaleCorr").nodeValue().toDouble(); + if(scorr != 0.0) { + cam.PixelSizeMm[0] *= scorr; + cam.PixelSizeMm[1] *= scorr; + } + } + else if (QString::compare(node.nodeName(),"ViewSettings")==0) + { + QDomNamedNodeMap attr = node.attributes(); + trackball.track.sca = attr.namedItem("TrackScale").nodeValue().section(' ',0,0).toFloat(); + nearPlane = attr.namedItem("NearPlane").nodeValue().section(' ',0,0).toFloat(); + farPlane = attr.namedItem("FarPlane").nodeValue().section(' ',0,0).toFloat(); + } + else if (QString::compare(node.nodeName(),"Render")==0) + { + QDomNamedNodeMap attr = node.attributes(); + rm.drawMode = (vcg::GLW::DrawMode) (attr.namedItem("DrawMode").nodeValue().section(' ',0,0).toInt()); + rm.colorMode = (vcg::GLW::ColorMode) (attr.namedItem("ColorMode").nodeValue().section(' ',0,0).toInt()); + rm.textureMode = (vcg::GLW::TextureMode) (attr.namedItem("TextureMode").nodeValue().section(' ',0,0).toInt()); + rm.lighting = (attr.namedItem("Lighting").nodeValue().section(' ',0,0).toInt() != 0); + rm.backFaceCull = (attr.namedItem("BackFaceCull").nodeValue().section(' ',0,0).toInt() != 0); + rm.doubleSideLighting = (attr.namedItem("DoubleSideLighting").nodeValue().section(' ',0,0).toInt() != 0); + rm.fancyLighting = (attr.namedItem("FancyLighting").nodeValue().section(' ',0,0).toInt() != 0); + rm.selectedFace = (attr.namedItem("SelectedFace").nodeValue().section(' ',0,0).toInt() != 0); + rm.selectedVert = (attr.namedItem("SelectedVert").nodeValue().section(' ',0,0).toInt() != 0); + } + node = node.nextSibling(); + } + + loadShot(QPair (shot,trackball.track.sca)); +} + +void GLArea::viewToClipboard() +{ + QClipboard *clipboard = QApplication::clipboard(); + Shot shot = shotFromTrackball().first; + + QDomDocument doc("ViewState"); + QDomElement root = doc.createElement("project"); + doc.appendChild( root ); + QDomElement shotElem = doc.createElement( "CamParam" ); + + vcg::Point3d tra = -(shot.Extrinsics.Tra()); + QString str = QString("%1 %2 %3 1").arg(tra[0]).arg(tra[1]).arg(tra[2]); + shotElem.setAttribute("SimTra", str); + vcg::Matrix44d rot = shot.Extrinsics.Rot(); + str = QString("%1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12 %13 %14 %15 %16 ") + .arg(rot[0][0]).arg(rot[0][1]) + .arg(rot[0][2]).arg(rot[0][3]) + .arg(rot[1][0]).arg(rot[1][1]) + .arg(rot[1][2]).arg(rot[1][3]) + .arg(rot[2][0]).arg(rot[2][1]) + .arg(rot[2][2]).arg(rot[2][3]) + .arg(rot[3][0]).arg(rot[3][1]) + .arg(rot[3][2]).arg(rot[3][3]); + shotElem.setAttribute( "SimRot", str); + + vcg::Camera &cam = shot.Intrinsics; + + shotElem.setAttribute( "Focal", cam.FocalMm); + + str = QString("%1 %2").arg(cam.k[0]).arg(cam.k[1]); + shotElem.setAttribute( "LensDist", str); + + str = QString("%1 %2").arg(cam.PixelSizeMm[0]).arg(cam.PixelSizeMm[1]); + shotElem.setAttribute( "ScaleF", str); + + str = QString("%1 %2").arg(cam.ViewportPx[0]).arg(cam.ViewportPx[1]); + shotElem.setAttribute( "Viewport", str); + + str = QString("%1 %2").arg((int)(cam.DistorCenterPx[0])).arg((int)(cam.DistorCenterPx[1])); + shotElem.setAttribute( "Center", str); + + str = QString("%1").arg((double) 1); + shotElem.setAttribute( "ScaleCorr", str); + + root.appendChild(shotElem); + + QDomElement settingsElem = doc.createElement( "ViewSettings" ); + settingsElem.setAttribute( "TrackScale", trackball.track.sca); + settingsElem.setAttribute( "NearPlane", nearPlane); + settingsElem.setAttribute( "FarPlane", farPlane); + root.appendChild(settingsElem); + + + QDomElement renderElem = doc.createElement( "Render"); + renderElem.setAttribute("DrawMode",rm.drawMode); + renderElem.setAttribute("ColorMode",rm.colorMode); + renderElem.setAttribute("TextureMode",rm.textureMode); + renderElem.setAttribute("Lighting",rm.lighting); + renderElem.setAttribute("BackFaceCull",rm.backFaceCull); + renderElem.setAttribute("DoubleSideLighting",rm.doubleSideLighting); + renderElem.setAttribute("FancyLighting",rm.fancyLighting); + renderElem.setAttribute("SelectedFace",rm.selectedFace); + renderElem.setAttribute("SelectedVert",rm.selectedVert); + root.appendChild(renderElem); + + clipboard->setText(doc.toString()); //.remove(QChar('\n'))); +} + +void GLArea::viewFromClipboard() +{ + QClipboard *clipboard = QApplication::clipboard(); + QString shotString = clipboard->text(); + + Shot shot; + + QDomDocument doc("StringDoc"); + doc.setContent(shotString); + + loadViewFromViewStateFile(shot, doc); +} + +QPair,float> GLArea::shotFromTrackball() +{ + Shot shot; + initializeShot(shot); + + double viewportYMm=shot.Intrinsics.PixelSizeMm[1]*shot.Intrinsics.ViewportPx[1]; + shot.Intrinsics.FocalMm = viewportYMm/(2*tanf(vcg::math::ToRad(fov/2))); + + float cameraDist = getCameraDistance(); + + //add the translation introduced by gluLookAt() (0,0,cameraDist)--------------------------------------- + //T(gl)*S*R*T(t) => SR(gl+t) => S R (S^(-1)R^(-1)gl + t) + //Add translation S^(-1) R^(-1)(gl) + //Shot doesn't introduce scaling + //--------------------------------------------------------------------- + shot.Extrinsics.SetTra( shot.Extrinsics.Tra() + (Inverse(shot.Extrinsics.Rot())*Point3d(0, 0, cameraDist))); + + Shot newShot = track2ShotCPU(shot, &trackball); + + ////Expressing scaling as a translation along z + ////k is the ratio between default scale and new scale + //double oldScale= 3.0f/meshDoc->bbox().Diag(); + //double k= oldScale/trackball.track.sca; + + ////Apply this formula + //// R(t+p) = kR'(t'+p) forall p, R=R', k is a costant + //// R(t)= kR(t') + //// t = k*t' + //Point3d t1 = newShot.Extrinsics.Tra(); + // + //Matrix44d rapM = Matrix44d().SetScale(k, k, k); + //Point3d t0 = rapM*t1; + + //newShot.Extrinsics.SetTra(t0); + + return QPair (newShot,trackball.track.sca); +} + +void GLArea::loadShot(const QPair,float> &shotAndScale){ + + Shot shot = shotAndScale.first; + + double viewportYMm=shot.Intrinsics.PixelSizeMm[1]*shot.Intrinsics.ViewportPx[1]; + fov = 2*(vcg::math::ToDeg(atanf(viewportYMm/(2*shot.Intrinsics.FocalMm)))); + + float cameraDist = getCameraDistance(); + + //reset trackball. The point of view must be set only by the shot + trackball.Reset(); + trackball.track.sca = shotAndScale.second; + + /*Point3f point = meshDoc->bbox().Center(); + Point3f p1 = ((trackball.track.Matrix()*(point-trackball.center))- Point3f(0,0,cameraDist));*/ + shot2Track(shot, cameraDist,trackball); + + //Expressing the translation along Z with a scale factor k + //Point3f p2 = ((trackball.track.Matrix()*(point-trackball.center))- Point3f(0,0,cameraDist)); + + ////k is the ratio between the distances along z of two correspondent points (before and after the traslazion) + ////from the point of view + //float k= abs(p2.Z()/p1.Z()); + + //float sca= trackball.track.sca/k; + //Point3f tra = trackball.track.tra; + // + //// Apply this formula: + //// SR(t+p) -v = k[S'R'(t'+p) -v] forall p, R=R', k is a costant + //// SR(t) -v = k[S'R(t') -v] + //// t' = 1/k* S'^-1St + (k-1)/k S'^-1*R^-1v + //Matrix44f s0 = Matrix44f().SetScale(trackball.track.sca,trackball.track.sca, trackball.track.sca); + //Matrix44f s1 = Matrix44f().SetScale(sca, sca, sca); + //Matrix44f r; + //trackball.track.rot.ToMatrix(r); + //Matrix44f rapM = Matrix44f().SetScale(1/k, 1/k, 1/k); + //Matrix44f rapM2 = Matrix44f().SetScale(1-1/k, 1-1/k, 1-1/k); + //Point3f t1 = rapM*Inverse(s1)*s0*tra + rapM2*Inverse(s1)*Inverse(r)*Point3f(0,0,cameraDist); + + //trackball.track.sca =sca; + //trackball.track.tra =t1 /*+ tb.track.rot.Inverse().Rotate(glLookAt)*/ ; + + update(); +} + +void GLArea::createOrthoView(QString dir) +{ + Shot view; + initializeShot(view); + + fov =5; + double viewportYMm = view.Intrinsics.PixelSizeMm[1]*view.Intrinsics.ViewportPx[1]; + view.Intrinsics.FocalMm = viewportYMm/(2*tanf(vcg::math::ToRad(fov/2))); //27.846098 equivalente a circa 60 gradi + + trackball.Reset(); + float newScale= 3.0f/meshDoc->bbox().Diag(); + trackball.track.sca = newScale; + trackball.track.tra = -meshDoc->bbox().Center(); + + vcg::Matrix44d rot; + + if(dir == tr("Top")) + rot.SetRotateDeg(90,Point3(1,0,0)); + else if(dir == tr("Bottom")) + rot.SetRotateDeg(90,Point3(-1,0,0)); + else if(dir == tr("Left")) + rot.SetRotateDeg(90,Point3(0,1,0)); + else if(dir == tr("Right")) + rot.SetRotateDeg(90,Point3(0,-1,0)); + else if(dir == tr("Front")) + rot.SetRotateDeg(0,Point3(0,1,0)); + else if(dir == tr("Back")) + rot.SetRotateDeg(180,Point3(0,1,0)); + + view.Extrinsics.SetRot(rot); + + float cameraDist = getCameraDistance(); + + //add the translation introduced by gluLookAt() (0,0,cameraDist)--------------------------------------- + //T(gl)*S*R*T(t) => SR(gl+t) => S R (S^(-1)R^(-1)gl + t) + //Add translation S^(-1) R^(-1)(gl) + //Shot doesn't introduce scaling + //--------------------------------------------------------------------- + view.Extrinsics.SetTra( view.Extrinsics.Tra() + (Inverse(view.Extrinsics.Rot())*Point3d(0, 0, cameraDist))); + + Shot shot = track2ShotCPU(view, &trackball); + + QPair shotAndScale = QPair (shot, trackball.track.sca); + loadShot(shotAndScale); +} + + diff --git a/src/meshlab/glarea.h b/src/meshlab/glarea.h index 22cdc59a8..b5d0abada 100644 --- a/src/meshlab/glarea.h +++ b/src/meshlab/glarea.h @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include "../common/interfaces.h" #include "../common/filterscript.h" @@ -69,6 +71,8 @@ class GLArea : public Viewer { Q_OBJECT + typedef vcg::Shot Shot; + public: GLArea(MultiViewer_Container *mvcont, RichParameterSet *current); ~GLArea(); @@ -83,7 +87,7 @@ public: vcg::Trackball trackball; vcg::Trackball trackball_light; - GLLogStream *log; + GLLogStream *log; FilterScript filterHistory; GLAreaSetting glas; QSize curSiz; @@ -302,7 +306,7 @@ private: float cfps; float lastTime; - QImage snapBuffer; + QImage snapBuffer; bool takeSnapTile; enum AnimMode { AnimNone, AnimSpin, AnimInterp}; @@ -310,8 +314,132 @@ private: int tileCol, tileRow, totalCols, totalRows; void setCursorTrack(vcg::TrackMode *tm); + //-----------Shot support---------------------------- +public: + QPair shotFromTrackball(); + bool viewFromFile(); + void createOrthoView(QString); + void viewToClipboard(); + void viewFromClipboard(); + void loadShot(const QPair &) ; + +private: + + float getCameraDistance(); + void initializeShot(Shot &shot); + void loadShotFromTextAlignFile(Shot &shot, QDomDocument &doc); + void loadViewFromViewStateFile(Shot &shot, QDomDocument &doc); + + + /* + Given a shot "refCamera" and a trackball "track", computes a new shot which is equivalent + to apply "refCamera" o "track" (via GPU). + */ + template + vcg::Shot track2ShotGPU(vcg::Shot &refCamera, vcg::Trackball *track){ + vcg::Shot view; + + double _near, _far; + _near = 0.1; + _far = 100; + + //get OpenGL modelview matrix after applying the trackball + GlShot >::SetView(refCamera, _near, _far); + glPushMatrix(); + track->GetView(); + track->Apply(); + vcg::Matrix44d model; + glGetv(GL_MODELVIEW_MATRIX, model); + glPopMatrix(); + GlShot >::UnsetView(); + + //get translation out of modelview + vcg::Point3d tra; + tra[0] = model[0][3]; tra[1] = model[1][3]; tra[2] = model[2][3]; + model[0][3] = model[1][3] = model[2][3] = 0; + + //get pure rotation out of modelview + double det = model.Determinant(); + double idet = 1/pow(det, 1/3.0); //inverse of the determinant + model *= idet; + model[3][3] = 1; + view.Extrinsics.SetRot(model); + + //get pure translation out of modelview + vcg::Matrix44d imodel = model; + vcg::Transpose(imodel); + tra = -(imodel*tra); + tra *= idet; + view.Extrinsics.SetTra(vcg::Point3::Construct(tra)); + + //use same current intrinsics + view.Intrinsics = refCamera.Intrinsics; + + return view; + } + + /* + Given a shot "refCamera" and a trackball "track", computes a new shot which is equivalent + to apply "refCamera" o "track" (via CPU). + */ + template + vcg::Shot track2ShotCPU(vcg::Shot &refCamera, vcg::Trackball *track){ + vcg::Shot view; + + double _near, _far; + _near = 0.1; + _far = 100; + + //get shot extrinsics matrix + vcg::Matrix44f shotExtr; + refCamera.GetWorldToExtrinsicsMatrix().ToMatrix(shotExtr); + + vcg::Matrix44f model2; + model2 = (shotExtr)* track->Matrix(); + vcg::Matrix44d model; + model2.ToMatrix(model); + + //get translation out of modelview + vcg::Point3d tra; + tra[0] = model[0][3]; tra[1] = model[1][3]; tra[2] = model[2][3]; + model[0][3] = model[1][3] = model[2][3] = 0; + + //get pure rotation out of modelview + double det = model.Determinant(); + double idet = 1/pow(det, 1/3.0); //inverse of the determinant + model *= idet; + model[3][3] = 1; + view.Extrinsics.SetRot(model); + + //get pure translation out of modelview + vcg::Matrix44d imodel = model; + vcg::Transpose(imodel); + tra = -(imodel*tra); + tra *= idet; + view.Extrinsics.SetTra(vcg::Point3::Construct(tra)); + + //use same current intrinsics + view.Intrinsics = refCamera.Intrinsics; + + return view; + } + + /* + TBD + */ + template + void shot2Track(const vcg::Shot &from, const float cameraDist, vcg::Trackball &tb){ + + vcg::Quaterniond qfrom; qfrom.FromMatrix(from.Extrinsics.Rot()); + + tb.track.rot = vcg::Quaternionf::Construct(qfrom); + tb.track.tra = (vcg::Point3f::Construct(-from.Extrinsics.Tra())); + tb.track.tra += vcg::Point3f::Construct(tb.track.rot.Inverse().Rotate(Point3f(0,0,cameraDist)))*(1/tb.track.sca); + } }; + + #endif diff --git a/src/meshlab/mainwindow_RunTime.cpp b/src/meshlab/mainwindow_RunTime.cpp index a34c4bbc6..f51e07869 100644 --- a/src/meshlab/mainwindow_RunTime.cpp +++ b/src/meshlab/mainwindow_RunTime.cpp @@ -109,8 +109,9 @@ void MainWindow::updateWindowMenu() windowsMenu->addSeparator(); - // Split/Unsplit SUBmenu + if((mdiarea-> subWindowList().size()>0)){ + // Split/Unsplit SUBmenu splitModeMenu = windowsMenu->addMenu(tr("&Split current view")); splitModeMenu->addAction(setSplitHAct); @@ -118,6 +119,26 @@ void MainWindow::updateWindowMenu() windowsMenu->addAction(setUnsplitAct); + // Link act + windowsMenu->addAction(linkViewersAct); + + // View From SUBmenu + viewFromMenu = windowsMenu->addMenu(tr("&View from")); + + viewFromMenu->addAction(viewTopAct); + viewFromMenu->addAction(viewBottomAct); + viewFromMenu->addAction(viewLeftAct); + viewFromMenu->addAction(viewRightAct); + viewFromMenu->addAction(viewFrontAct); + viewFromMenu->addAction(viewBackAct); + + // View From File act + windowsMenu->addAction(viewFromFileAct); + + // Copy and paste shot acts + windowsMenu->addAction(copyShotToClipboardAct); + windowsMenu->addAction(pasteShotFromClipboardAct); + MultiViewer_Container *mvc = currentDocContainer(); if(mvc) { @@ -127,6 +148,10 @@ void MainWindow::updateWindowMenu() setSplitHAct->setEnabled(current->size().height()/2 > current->minimumSizeHint().height()); setSplitVAct->setEnabled(current->size().width()/2 > current->minimumSizeHint().width()); + linkViewersAct->setEnabled(currentDocContainer()->viewerCounter()>1); + if(currentDocContainer()->viewerCounter()==1) + linkViewersAct->setChecked(false); + windowsMenu->addSeparator(); } } @@ -452,6 +477,38 @@ void MainWindow::unsplitFromHandle(QAction * qa) setUnsplit(); } +void MainWindow::linkViewers() +{ + MultiViewer_Container *mvc = currentDocContainer(); + mvc->updateTrackballInViewers(); +} + +void MainWindow::viewFrom(QAction *qa) +{ + MultiViewer_Container *mvc = currentDocContainer(); + ((GLArea*)mvc->currentView())->createOrthoView(qa->text()); +} + +void MainWindow::readViewFromFile() +{ + MultiViewer_Container *mvc = currentDocContainer(); + ((GLArea*)mvc->currentView())->viewFromFile(); + updateMenus(); +} + +void MainWindow::copyViewToClipBoard() +{ + MultiViewer_Container *mvc = currentDocContainer(); + ((GLArea*)mvc->currentView())->viewToClipboard(); +} + +void MainWindow::pasteViewFromClipboard() +{ + MultiViewer_Container *mvc = currentDocContainer(); + ((GLArea*)mvc->currentView())->viewFromClipboard(); + updateMenus(); +} + void MainWindow::dragEnterEvent(QDragEnterEvent *event) { //qDebug("dragEnterEvent: %s",event->format()); diff --git a/src/meshlab/multiViewer_Container.cpp b/src/meshlab/multiViewer_Container.cpp index 8c39ac1d5..d0d273373 100644 --- a/src/meshlab/multiViewer_Container.cpp +++ b/src/meshlab/multiViewer_Container.cpp @@ -288,3 +288,12 @@ void MultiViewer_Container::updateAll(){ void MultiViewer_Container::update(int id){ getViewer(id)->update(); } + +void MultiViewer_Container::updateTrackballInViewers() +{ + QPair shotAndScale = ((GLArea*)currentView())->shotFromTrackball(); + foreach(Viewer* viewer, viewerList) + if(viewer->getId() != currentId){ + ((GLArea*) viewer)->loadShot(shotAndScale); + } +} diff --git a/src/meshlab/multiViewer_Container.h b/src/meshlab/multiViewer_Container.h index 7d40d00c2..cd7b8e814 100644 --- a/src/meshlab/multiViewer_Container.h +++ b/src/meshlab/multiViewer_Container.h @@ -66,7 +66,7 @@ class MultiViewer_Container : public Splitter { Q_OBJECT - /*typedef vcg::Shot Shot;*/ + typedef vcg::Shot Shot; public: MultiViewer_Container(QWidget *parent); @@ -85,6 +85,8 @@ public: Viewer* getViewer(int id); int getViewerByPicking(QPoint); + void updateTrackballInViewers(); + MeshDocument meshDoc; int currentId;