docs: static NodeInfo selectClosestSide( NodeInfo a , NodeInfo b ) {
  
  		double ratio = 1.7321;
  
  		NodeInfo best = null;
  		double bestDistance = Double.MAX_VALUE;
  		Edge bestEdgeA = null;
  		Edge bestEdgeB = null;
  
  		for (int i = 0; i < a.edges.size; i++) {
  			NodeInfo aa = a.edges.get(i).target;
  			if( aa.marked ) continue;
  
  			for (int j = 0; j < b.edges.size; j++) {
  				NodeInfo bb = b.edges.get(j).target;
  				if( bb.marked ) continue;
  
  				if( aa == bb ) {
  					double da = EllipsesIntoClusters.axisAdjustedDistanceSq(a.ellipse,aa.ellipse);
  					double db = EllipsesIntoClusters.axisAdjustedDistanceSq(b.ellipse,aa.ellipse);
  
  					da = Math.sqrt(da);
  					db = Math.sqrt(db);
  
  					double max,min;
  					if( da>db) {
  						max = da;min = db;
  					} else {
  						max = db;min = da;
  					}
  
  					// see how much it deviates from the ideal length with no distortion
  					double diffRatio = Math.abs(max-min*ratio)/max;
  					if( diffRatio > 0.25 )
  						continue;
  
  					// TODO reject if too far
  					double d = da+db;
  
  					if( d < bestDistance ) {
  						bestDistance = d;
  						best = aa;
  						bestEdgeA = a.edges.get(i);
  						bestEdgeB = b.edges.get(j);
  					}
  					break;
  				}
  			}
  		}
  
  		// check the angles
  		if( best != null ) {
  			double angleA = UtilAngle.distanceCW(bestEdgeA.angle,bestEdgeB.angle);
  
  			if( angleA < Math.PI*0.25 ) // expected with zero distortion is 30 degrees
  				return best;
  			else
  				return null;
  		}
  
  		return null;
  	}