docs: @Override
  	public boolean process(PairwiseImageGraph pairwiseGraph ) {
  		this.graph = new MetricSceneGraph(pairwiseGraph);
  		for (int i = 0; i < graph.edges.size(); i++) {
  			decomposeEssential(graph.edges.get(i));
  		}
  
  		declareModelFitting();
  
  		for (int i = 0; i < graph.edges.size(); i++) {
  			Motion e = graph.edges.get(i);
  			e.triangulationAngle = medianTriangulationAngle(e);
  		}
  
  		if( verbose != null )
  			verbose.println("Selecting root");
  		// Select the view which will act as the origin
  		View origin = selectOriginNode();
  		// Select the motion which will define the coordinate system
  		Motion baseMotion = selectCoordinateBase( origin );
  
  		this.graph.sanityCheck();
  
  		if( verbose != null )
  			verbose.println("Stereo triangulation");
  		// Triangulate features in all motions which exceed a certain angle
  		for (int i = 0; i < graph.edges.size() && !stopRequested ; i++) {
  			Motion e = graph.edges.get(i);
  			if( e.triangulationAngle > Math.PI/10 || e == baseMotion) {
  				triangulateStereoEdges(e);
  				if( verbose != null ) {
  					int a = e.viewSrc.index;
  					int b = e.viewDst.index;
  					verbose.println("   Edge[" + i + "] "+a+"->"+b+"  feat3D="+e.stereoTriangulations.size());
  				}
  			}
  		}
  		if( stopRequested )
  			return false;
  
  		if( verbose != null )
  			verbose.println("Defining the coordinate system");
  
  		// Using the selecting coordinate frames and triangulated points define the coordinate system
  		defineCoordinateSystem(origin, baseMotion);
  		if( stopRequested )
  			return false;
  
  		if( verbose != null )
  			verbose.println("Estimate all features");
  
  		// Now estimate all the other view locations and 3D features
  		estimateAllFeatures(origin, baseMotion.destination(origin));
  		if( stopRequested )
  			return false;
  
  		// Convert the graph into the output format
  		convertToOutput(origin);
  
  		return viewsAdded.size() >= 2;
  	}