Utils essentials

No problem :slight_smile: I know my Util methods aren’t optimized, it just hasn’t bothered me really. I’m already updating my class though.

Ken Perlin’s ‘ease’ functions:

For inputs 0 <= t <= 1, returns a smooth value on [0,1].

The first version is first order continuous, the second is continous is all derv.


public static final float
perlinEase(float t)
{
  return (t*t*(3.f-(t+t)));
}

public static final float
perlinEase2(float t)
{
  float t3 = t*t*t;

  return t3*(10.f+t*(-15.f+6.f*t));
}

Cubic Spline interpolation :

	
// Takes in v0 and v3 points with v1 and v2 control points. t is 0-1.
// Returns the interpolated at t.
public static float cubicSplineInterpolate(float v0, float v1, float v2, float v3, float t) {
		float A = v3 - (3f * v2) + (3f * v1) - v0;
		float B = (3f * v2) - (6f * v1) + (3f * v0);
		float C = (3f * v1) - (3f * v0);
		float D = v0;

		float v = (A * (t * t * t)) + (B * (t * t)) + (C * t) + D;

		return v;
	}

/**
 * Calculates the mean and concentration of a number of angles
 * 
 * @param angles
 *           An array of angles, in radians
 * @return A two-element array { mean, concentration }. The
 *         concentration metric will be 1 if all input angles are
 *         identical and zero of the angles are distributed evenly
 *         around the circle. I doubt it varies linearly though.
 */
public static float[] meanAngle( float[] angles )
{
	double meanX = 0;
	double meanY = 0;

	for( int i = 0; i < angles.length; i++ )
	{
		meanY += Math.sin( angles[ i ] );
		meanX += Math.cos( angles[ i ] );
	}

	meanX /= angles.length;
	meanY /= angles.length;

	float[] results = new float[ 2 ];

	results[ 0 ] = ( float ) Math.atan2( meanY, meanX );
	results[ 1 ] = ( float ) Math.sqrt( meanX * meanX + meanY * meanY );

	return results;
}

Too big to be a snippet, and not my code, but too nice to leave out: Riven’s LUT trig methods

writing JPG with specified quality, to any Outputstream (not only to a file)


   public static void writeJPG(BufferedImage img, final OutputStream out, float quality) throws IOException
   {
      ImageOutputStreamImpl output = new ImageOutputStreamImpl()
      {
         @Override
         public int read(byte[] b, int off, int len) throws IOException
         {
            throw new UnsupportedOperationException();
         }

         @Override
         public int read() throws IOException
         {
            throw new UnsupportedOperationException();
         }

         @Override
         public void write(byte[] buf, int off, int len) throws IOException
         {
            out.write(buf, off, len);
         }

         @Override
         public void write(int b) throws IOException
         {
            out.write(b);
         }

         @Override
         public void flush() throws IOException
         {
            super.flush();

            out.flush();
         }

         @Override
         public void close() throws IOException
         {
            super.close();

            out.close();
         }
      };

      Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName("jpeg");
      ImageWriter writer = iter.next();
      ImageWriteParam iwp = writer.getDefaultWriteParam();
      iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
      iwp.setCompressionQuality(quality);

      writer.setOutput(out);
      IIOImage image = new IIOImage(img, null, null);
      writer.write(null, image, iwp);
      writer.dispose();
      output.close();
   }

Sorry, was confused with field.setAccessible(true) on a publicly accessible field :persecutioncomplex:

@Riven

Didn’t you create a method (for your signature trickery) that writes an Image[] to an animated GIF? Any chance that’s published somewhere?

This is a method I just restructured. I ran a few test cases on it, and it seems to work. (No guarantees though, as I’ve often thought I finally cracked the solution to this but after a while it seems to fail, but pretty sure now ;D)

I’ve sometimes gone mad trying to figure out… into what direction I should interpolate a rotation, given a object facing angleFrom but needs to face a new angleTo.

Example, a defense-tower in a game that has acquired a new target and must look at it. You don’t want it to rotate a 350° clockwise if it could have rotated 10° counter-clockwise!

With this method you can determine the rotation direction.

false = rotate clockwise
true = rotate counter-clockwise


public static boolean shouldRotateCounterClockwise(float angleFrom, float angleTo) {
	float diff = (angleFrom - angleTo) % 360;
	return diff > 0 ? diff < 180 : diff < -180;
}

Maybe my brain is not in gear, but doesn’t the following work:


  float diff = (angleFrom-angleTo) % 360;

  if (diff > 0) return diff<180;  
  
  return diff < -180;
 

Thanks. I’ve updated my function, and made my own adjustments as well :smiley:

Creates a MD5-Hash for the given String


	public static final String md5HashFromString(String text) {
		try {
			MessageDigest md5 = MessageDigest.getInstance("MD5");
			md5.reset();
			md5.update(text.getBytes("UTF-8"));
			byte[] result = md5.digest();
			
			StringBuilder sb = new StringBuilder();
			
			for (int i = 0; i < result.length; i += 1) {
				String value = Integer.toHexString(0xFF & result[i]);
				if (value.length() < 2) {
					value = "0" + value;
				}
				sb.append(value);
			}
			
			return sb.toString();
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return null;
	}

Use Non-Power Of 2 Textures.
On Android, this converts a Non Pow of 2 texture to and OpenGL(ES) ready Bitmap.
No more batch image resizing :slight_smile:


	private Bitmap glBitmap(Bitmap bitmap) {
		Bitmap pbmp;
		int texWidth = get2Fold(bitmap.getWidth());
		int texHeight = get2Fold(bitmap.getHeight());
		pbmp = Bitmap.createBitmap(texWidth, texHeight, bitmap.getConfig());
		for (int y = 0; y < bitmap.getHeight(); y++) {
			for (int x = 0; x < bitmap.getWidth(); x++) {
				pbmp.setPixel(x, y, bitmap.getPixel(x, y));
			}
		}
		return pbmp;
	}


	public static int get2Fold(int fold) {
	    int ret = 2;
	    while (ret < fold) {
	        ret *= 2;
	    }
	    return ret;
	}

Your texture will then use the texture coordinates:


widthRatio = (float) width / (texWidth < 1 ? width : texWidth);	
heightRatio = (float) height / (texHeight < 1 ? height : texHeight);

Where width is the original image with and texWidth is the with of the new Pow Of 2 texture Bitmap return by glBitmap()…


	public static Point lineIntersect(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) {
		double denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
		if (denom == 0.0) { // Lines are parallel.
			return null;
		}
		double ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3))/denom;
		double ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3))/denom;
        if (ua >= 0.0f && ua <= 1.0f && ub >= 0.0f && ub <= 1.0f) {
            // Get the intersection point.
            return new Point((int) (x1 + ua*(x2 - x1)), (int) (y1 + ua*(y2 - y1)));
        }

		return null;
	}

line intersection algo

Great idea for a thread! I’ll add my most used utility…

I often find myself needing to randomize amongst elements in a set with weighted probabilities; if probabilities are all equal, then Random::nextInt(n) is the way to go, but if you need to draw from a different distribution it’s actually bit of work to get something that works right.

This code has only been lightly tested in its current form (I changed it a bit from where I last used it, mainly to accept varargs), and I have no guarantees that it’s optimal, but I did run some basic tests and it appears to be working fairly well (seems correct, and runs at several millions of picks per second as long as the probabilities array is less than 50 or so, even using the garbage-producing version), and this is the several-th iteration of this code, so it shouldn’t be too buggy; I use some variant of this all over the place both in game code and Monte Carlo simulation, so it might be useful to someone:


	/**
	 * Spin a spinner with the given relative probabilities, get the index that results.  This
	 * method does not alter the passed array.
	 * <pre>
	 * normalizedSpinner(10, 20, 30) => 1/6 chance of 0, 1/3 chance of 1, 1/2 chance of 2
	 * normalizedSpinner(1,1,2) => 1/4 chance of 0, 1/4 chance of 1, 1/2 chance of 2
	 * </pre>
	 * Note: during intermediate steps, this method will cause two float[] creations, the
	 * same length as the probabilities array.  If creation is a concern, use {@link #spinner(float[], float[])}
	 * to pass your own pre-allocated intermediate array and handle the probability normalization yourself. 
	 * Also remember that unless probabilities is passed as an array, Java's varargs will create another
	 * intermediate array.
	 * 
	 * @param probabilities a list of relative probabilities
	 * @return the index of the event that is randomly chosen based on the provided probabilities
	 */
	public static int normalizedSpinner(float ... probabilities) {
		float sum = 0.0f;
		for (int i=0; i<probabilities.length; ++i) {
			sum += probabilities[i];
		}
		if (sum == 0.0f) {
			throw new IllegalArgumentException("At least one probability must be non-zero.");
		} else if (sum < 0.0f) {
			throw new IllegalArgumentException("Probabilities may not be negative.");
		}
		float[] normProbs = new float[probabilities.length];
		for (int i=0; i<probabilities.length; ++i) {
			normProbs[i] = probabilities[i] / sum;
		}
		return spinner(normProbs);
	}
	
    /**
     * Spin a spinner with the given probabilities, get the index that results.
     * Sum of probabilities should add up to 1f.
     * 
     * If the sum of probabilities is less than 1, the last index gets all the
     * remaining probability.
     * e.g. spinner(0.5f, 0.3f) => 50% chance of 0, 50% chance of 1
     * 
     * If the sum of probabilities is greater than 1, the probabilities are clipped
     * at 1.
     * 
     * e.g. spinner(0.5f, 0.3f, 0.5f) => 50% chance of 0, 30% chance of 1, 20% chance of 2 (extra 30% discarded)
     * 
     * This method creates an intermediate float array the same length as probabilities; if garbage
     * creation is a concern, use {@link #spinner(float[], float[])} instead, and provide a pre-allocated
     * array of the correct length as the first parameter.
     * 
     * @param probabilities a list of probabilities that should add up to 1
     * @return the index of the event that is randomly chosen based on the provided probabilities
     */
    public static int spinner(float ... probabilities) {
        float[] mins = new float[probabilities.length];
        return spinner(mins, probabilities);
    }
    
    /**
     * Used instead of {@link #spinner(float...)} to avoid garbage creation by manually supplying
     * intermediate array.
     * 
     * @param auxiliaryArray a pre-allocated array to use for intermediate step that should
     * have at least the same length as the probabilities array (used to avoid intermediate allocations)
     * @param probabilities a list of probabilities that should add up to 1
     * @return the index of the event that is chosen
     * @see Spinner#spinner(float...)
     */
    public static int spinner(float[] auxiliaryArray, float[] probabilities) {
    	if (auxiliaryArray.length < probabilities.length){
    		throw new IllegalArgumentException("Auxiliary array must have at least the same length as probabilities array.");
    	}
    	float sum = 0.0f;
        float[] mins = auxiliaryArray;
        for (int i = 0; i < probabilities.length; ++i) {
            if (probabilities[i] < 0.0f) {
                throw new IllegalArgumentException("Probabilities must be positive; received " + probabilities[i] +
                        " as parameter " + i + ".");
            }
            mins[i] = sum;
            sum += probabilities[i];
        }
        double randomNumber = Math.random();
        for (int i = probabilities.length - 1; i > 0; --i) {
            if (randomNumber >= mins[i]) {
                return i;
            }
        }
        return 0;
    }

Sorry, more Javadoc than code, I know…

The idea is that you’re spinning a spinner (like on a game board or something) with the passed probabilities, and the result is the array index of the probability that gets picked. Probably not the clearest name, idunno.

Re: the different functions, normalizedSpinner first normalizes the passed probabilities to sum to 1, and the two-array version lets you pass your own auxiliary array to be used internally so that no garbage is created - when I use these methods, I’m sometimes running hundreds of thousands of trials over distributions with thousands of probabilities, so garbage becomes a huge issue; obviously in those cases I also swap out the Math.random() call with a faster RNG, and sometimes after debugging I strip the parameter checking code, too, though those branches are usually very predictable so it shouldn’t make a big difference.

A simple circle-circle collision check. Not sure about it’s performance, but it surely looks simple enough. Just calculates the euclidean distance between the origin of the two circles, subtracting the two radius from the distance will give either a negative or positive distance. Negative means they collide, positive means they don’t.


       // Check if circle (x1,y1,radius1) collides with another circle of (x2,y2,radius2).
	public static boolean doCirclesCollide(float x1, float y1, float radius1, float x2, float y2, float radius2) {
		float d = euclideanDistance(x1, y1, x2, y2);

		d -= radius1 + radius2;

		return d < 0;
	}

        // Added dependency
	public static float euclideanDistance(float x1, float y1, float x2, float y2) {
		float a = x1-x2;
		float b = y1-y2;
		return (float) Math.sqrt(a*a + b*b);
	}



edit: use Riven’s function below.

To see whether two circles (or spheres) intersect, there is no need to calculate the square root:


public static boolean doCirclesCollide(float x1, float y1, float radius1, float x2, float y2, float radius2)
{
    float dx = x2 - x1;
    float dy = y2 - y1;
    float d = radius1 + radius2;
    return (dx * dx + dy * dy) < (d * d);
}

This function should really never be used, actually I never use it. But if you really have to find out where the lerp interpolation is at, that is at what time, then you can simply do a little check that goes like this:

For a interpolation between a and b, currently being at x, then lerpTime gives you t of that.

(You can decide if you want the overflow checks or not, just remove all the if’s and return t directly)


        // Returns t of x between a and b.
	public static float lerpTime(float a, float b, float x) {
		if (a == x)
			return 0;
		else if (a == b)
			return 1;

		float t = (x - a) / (b - a);

		if (t >= 1)
			return 1;
		else
			return t;
	}

Not trying to be harassing :), but calling a method ‘lerp’ when it does the ‘inverse of a lerp’ would be highly confusing. Further, it’s not really related to ‘time’ in any way. There’s the code I use:


   public static final float lerp(float t, float a, float b)
   {
      return a + t * (b - a);
   }

   public static final float invLerp(float cur, float min, float max)
   {
      return (cur - min) / (max - min);
   }

   public static final float interpolate(float cur, float min, float max, float startValue, float endValue)
   {
      return lerp(invLerp(cur, min, max), startValue, endValue);
   }

   public static final float cappedInterpolate(float cur, float min, float max, float startValue, float endValue)
   {
      if (cur < min)
         return startValue;
      if (cur > max)
         return endValue;
      return interpolate(cur, min, max, startValue, endValue);
   }

The only way to squeeze out good code is to post such a bad code that it offends the good programmers which forces them to post corrections :wink:

On that note: here I have this function that I never used, but I couldn’t force myself to delete it:


   public static final double curve(double distance, double topDistance, double margin, double power)
   {
      // Shape: __________________/\_____________________
      //     _/\_ == pow(sin(n), power)   

      // value 0 at topDistance-margin
      // value 1 at topDistance
      // value 0 at topDistance+margin

      double min = topDistance - margin;
      double max = topDistance;
      double ratio = (distance - min) / (max - min);
      double angle = ratio * 0.5 * Math.PI;
      if (angle < 0.0 || angle > Math.PI)
         return 0.0;
      double sinCurve = Math.sin(angle);
      return Math.pow(sinCurve, power);
   }