Fill triangle with 3 color gradient in Java


I was not able to find a solution for this problem. I would like to paint a filled triangle in Java with gradient where each corner has different color. Something like this:

enter image description here

I found some posts online but I was not able to figure out how to do the gradient in Java. The problem is that in Java you can do GradientPaint only from one color to another, which is not suitable to fill a triangle.

So far I have come up with this code which does not work as expected:

triangle.p1().getValue();
Color color1 = calculateColor(triangle.p1().getValue());
Color color2 = calculateColor(triangle.p2().getValue());
Color color3 = calculateColor(triangle.p3().getValue());
Color transparent = new Color(0, 0, 0, 0);
Polygon polygon = new Polygon(
        new int[]{(int) triangle.p1().x(), (int) triangle.p2().x(), (int) triangle.p3().x()},
        new int[]{(int) triangle.p1().y(), (int) triangle.p2().y(), (int) triangle.p3().y()},
        3);
GradientPaint gradient1 = new GradientPaint(
        (float) triangle.p1().x(), (float) triangle.p1().y(), color1,
        (float) triangle.p2().x(), (float) triangle.p2().y(), transparent);
GradientPaint gradient2 = new GradientPaint(
        (float) triangle.p2().x(), (float) triangle.p2().y(), color2,
        (float) triangle.p3().x(), (float) triangle.p3().y(), transparent);
GradientPaint gradient3 = new GradientPaint(
        (float) triangle.p3().x(), (float) triangle.p3().y(), color3,
        (float) triangle.p1().x(), (float) triangle.p1().y(), transparent);
graphics2d.setPaint(gradient1);
graphics2d.fill(polygon);
graphics2d.setPaint(gradient2);
graphics2d.fill(polygon);
graphics2d.setPaint(gradient3);
graphics2d.fill(polygon);

Here is the result I am getting: points A and B have the same color but the triangles adjacent to AB have different color

Some threads that mention similar thing: Triangle Gradient With Core Graphics and Java 3 Color Gradient


Answers:


This is based on the idea that if you pick any color inside the triangle it will create three areas from the three points of the triangle. Therefore we are extendng the principle of linear interpolation

color=(distance to p1)/(distance p1, p2)*c1+(distance to p2)/distance(p1, p2)*c2;

to the 2-D plane. Thus the weighting coefficents will be areas:

public int areaTriangle(int x1, int y1, int x2, int y2, int x3, int y3) {
  return (int)(0.5*Math.abs((x1-x3)*(y2-y1)-(x1-x2)*(y3-y1)));
}

BufferedImage b=new BufferedImage(500, 500, BufferedImage.TYPE_INT_RGB);
Polygon pl=new Polygon();
pl.addPoint(100, 100); pl.addPoint(200, 150); pl.addPoint(150, 200);
Rectangle r=pl.getBounds();
int a=areaTriangle(pl.xpoints[0], pl.ypoints[0], pl.xpoints[1], pl.ypoints[1], pl.xpoints[2], pl.ypoints[2]);
int[] c1={255, 0, 0}, c2={0, 255, 0}, c3={0, 0, 255};
for(i=0; i<r.width; i++)
for(j=0; j<r.height; j++)
  if(pl.contains(r.x+i, r.y+j)) {
    int ix=r.x+i, jy=r.y+j;
    int a1=areaTriangle(ix, jy, pl.xpoints[0], pl.ypoints[0], pl.xpoints[1], pl.ypoints[1]);
    int a2=areaTriangle(ix, jy, pl.xpoints[0], pl.ypoints[0], pl.xpoints[2], pl.ypoints[2]);
    int a3=areaTriangle(ix, jy, pl.xpoints[1], pl.ypoints[1], pl.xpoints[2], pl.ypoints[2]);

    int[] c=new int[3];
//      for(l=0; l<3; l++) c[l]=(int)((1-1.0*a1/a)*c1[l]+(1-1.0*a2/a)*c2[l]+(1-1.0*a3/a)*c3[l]);
    for(l=0; l<3; l++) c[l]=(int)((1.0*a1/a)*c3[l]+(1.0*a2/a)*c2[l]+(1.0*a3/a)*c1[l]);
    b.setRGB(ix, jy, 0xff000000|(c[0]<<16)|(c[1]<<8)|c[2]);
  }

If you try the commented line you will get the three complementary colors.