docs: protected void findPeak( float cx , float cy , float[] meanColor ) {
  
  		history.reset();
  		history.grow().set(cx,cy);
  
  		for( int i = 0; i < maxIterations; i++ ) {
  			float total = 0;
  			float sumX = 0, sumY = 0;
  
  			Arrays.fill(sumColor,0);
  
  			int kernelIndex = 0;
  
  			float x0 = cx - radiusX;
  			float y0 = cy - radiusY;
  
  			// If it is not near the image border it can use faster techniques
  			if( interpolate.isInFastBounds(x0, y0) &&
  					interpolate.isInFastBounds(x0 + widthX - 1, y0 + widthY - 1)) {
  				for( int yy = 0; yy < widthY; yy++ ) {
  					for( int xx = 0; xx < widthX; xx++ ) {
  						float ds = spacialTable[kernelIndex++];
  						interpolate.get(x0 + xx, y0 + yy, pixelColor);
  						float dc = distanceSq(pixelColor,meanColor)/ maxColorDistanceSq;
  						float weight = dc > 1 ? 0 : weight((ds+dc)/2f);
  						total += weight;
  						sumX += weight*(xx+x0);
  						sumY += weight*(yy+y0);
  						sumColor(sumColor, pixelColor,weight);
  					}
  				}
  			} else {
  				// Perform more sanity checks here for the image edge.  Edge pixels are handled by skipping them
  				for( int yy = 0; yy < widthY; yy++ ) {
  					float sampleY = y0+yy;
  					// make sure it is inside the image
  					if( sampleY < 0 ) {
  						kernelIndex += widthX;
  						continue;
  					} else if( sampleY > image.height-1) {
  						break;
  					}
  					for( int xx = 0; xx < widthX; xx++ , kernelIndex++) {
  						float sampleX = x0+xx;
  
  						// make sure it is inside the image
  						if( sampleX < 0 ||  sampleX > image.width-1 ) {
  							continue;
  						}
  
  						float ds = spacialTable[kernelIndex];
  						interpolate.get(x0 + xx, y0 + yy, pixelColor);
  						float dc = distanceSq(pixelColor,meanColor)/ maxColorDistanceSq;
  						float weight = dc > 1 ? 0 : weight((ds+dc)/2f);
  						total += weight;
  						sumX += weight*(xx+x0);
  						sumY += weight*(yy+y0);
  						sumColor(sumColor, pixelColor,weight);
  					}
  				}
  			}
  
  			if( total == 0 )
  				break;
  
  			float peakX = sumX/total;
  			float peakY = sumY/total;
  
  			if( fast ) {
  				history.grow().set(peakX,peakY);
  
  				// see if it has already been here before
  				int px = (int)(peakX+0.5f);
  				int py = (int)(peakY+0.5f);
  
  				int index = pixelToMode.getIndex(px,py);
  				int modeIndex = pixelToMode.data[index];
  				if( modeIndex != -1 ) {
  					// it already knows the solution so stop searching
  					Point2D_I32 modeP = modeLocation.get(modeIndex);
  					this.modeX = modeP.x;
  					this.modeY = modeP.y;
  					return;
  				}
  			}
  
  			// move on to the next iteration
  			float dx = peakX-cx;
  			float dy = peakY-cy;
  
  			cx = peakX; cy = peakY;
  			meanColor(sumColor,meanColor,total);
  
  			if( Math.abs(dx) < convergenceTol && Math.abs(dy) < convergenceTol ) {
  				break;
  			}
  		}
  
  		this.modeX = cx;
  		this.modeY = cy;
  	}