docs: void connect(List<EllipseInfo> ellipses) {
  		for (int i = 0; i < ellipses.size(); i++) {
  			EllipseInfo info1 = ellipses.get(i);
  			EllipseRotated_F64 e1 = info1.ellipse;
  			Node node1 = nodes.get(i);
  
  			// Only search the maximum of the major axis times two
  			// add a fudge factor.  won't ever be perfect
  			double maxDistance = e1.a * maxDistanceToMajorAxisRatio;
  			maxDistance *= maxDistance;
  
  			searchResults.reset();
  			search.findNearest( ellipses.get(i), maxDistance, Integer.MAX_VALUE, searchResults );
  
  			// if this node already has a cluster look it up, otherwise create a new one
  			List<Node> cluster1;
  
  			if( node1.cluster == -1 ) {
  				node1.cluster = clusters.size;
  				cluster1 = clusters.grow();
  				cluster1.clear();
  				cluster1.add( node1 );
  			} else {
  				cluster1 = clusters.get( node1.cluster );
  			}
  
  			double edge1 = info1.averageOutside-info1.averageInside;
  
  			// only accept ellipses which have a similar size
  			for (int j = 0; j < searchResults.size(); j++) {
  				NnData<EllipseInfo> d = searchResults.get(j);
  				EllipseInfo info2 = ellipses.get(d.index);
  				EllipseRotated_F64 e2 = info2.ellipse;
  				if( e2 == e1 )
  					continue;
  
  				// see of they are already connected
  				if( node1.connections.indexOf(d.index) != -1 ) {
  					continue;
  				}
  
  				// test the appearance of the ellipses edge
  				double edge2 = info2.averageOutside-info2.averageInside;
  				double intensityRatio = Math.abs(edge1-edge2)/Math.max(edge1,edge2);
  
  				if( intensityRatio > edgeIntensitySimilarityTolerance)
  					continue;
  
  				// the initial search was based on size of major axis.  Now prune and take in account the distance
  				// from the minor axis
  				if( axisAdjustedDistanceSq(e1,e2) > maxDistance ) {
  					continue;
  				}
  
  				// TODO take in in account how similar their orientation is, but less important when they are circular
  				//      somehow work into aspect ratio test?
  
  				// smallest shape divided by largest shape
  				double ratioA = e1.a > e2.a ? e2.a / e1.a : e1.a / e2.a;
  				double ratioB = e1.b > e2.b ? e2.b / e1.b : e1.b / e2.b;
  
  				if( ratioA < sizeSimilarityTolerance && ratioB < sizeSimilarityTolerance ) {
  					continue;
  				}
  
  				// axis ratio similarity check
  				double ratioC = (e1.a*e2.b)/(e1.b*e2.a);
  				if( ratioC > 1 ) ratioC = 1.0/ratioC;
  
  				if( ratioC < ratioSimilarityTolerance ) {
  					continue;
  				}
  
  				// Apply rule which combines two features
  				if( intensityRatio + (1-ratioC) >
  						(edgeIntensitySimilarityTolerance/1.5+(1-ratioSimilarityTolerance)) )
  					continue;
  
  				int indexNode2 = d.index;
  				Node node2 = nodes.get(indexNode2);
  
  				// node2 isn't in a cluster already.  Add it to this one
  				if( node2.cluster == -1 ) {
  					node2.cluster = node1.cluster;
  					cluster1.add( node2 );
  					node1.connections.add( indexNode2 );
  					node2.connections.add( i );
  				} else if( node2.cluster != node1.cluster ) {
  					// Node2 is in a different cluster.  Merge the clusters
  					joinClusters( node1.cluster , node2.cluster );
  					node1.connections.add( indexNode2 );
  					node2.connections.add( i );
  				} else {
  					node1.connections.add( indexNode2 );
  					node2.connections.add( i );
  				}
  			}
  		}
  	}