Idea: A Triangle is a very easy shape but it is very hard to distinguish the shape in an image by a computer, but a rectangle is much easier to be processed by a computer, thus we should just make a rectangle from two triangles and then we will check that the rectangle area is presented and artifacts-free, also we can check that there are not any points outside of the area..
I have written some Java code to check the idea. There is not a method in the java.awt.Graphics object to fill a triangle thus I have written such one:
public class TriangleFiller { /** * The method fills a triangle area and we check that the method fills a triangle * @param graphics the graphics context * @param xcoords an array contains the x coordinates for vertices (must have 3 positions) * @param ycoords an array contains the y coordinates for vertices (must have 3 positions) */ public static void fillTriangle(final Graphics graphics, int[] xcoords, int[] ycoords) { if (xcoords.length != 3 || ycoords.length != 3) { throw new IllegalArgumentException("Triangle must have 3 points"); } final Polygon polygon = new Polygon(xcoords, ycoords, 3); // we need use draw+fill because the fill operation fills the inside area graphics.drawPolygon(polygon); graphics.fillPolygon(polygon); } }
Then I wrote a unit test to make the "visual check" of the method just on an image and it works well:
package com.igormaznitsa.testtriangle; import java.awt.*; import java.awt.image.*; import java.io.*; import javax.imageio.ImageIO; import static org.junit.Assert.*; import org.junit.Test; public class TriangleFillerTest { private boolean checkTriangleCornerPoints(final BufferedImage baseRGBImage, final int pointColor, final int[] xVerticies, final int[] yVerticies) { for (int pointIndex = 0; pointIndex < 3; pointIndex++) { final int x = xVerticies[pointIndex]; final int y = yVerticies[pointIndex]; if ((baseRGBImage.getRGB(x, y) & 0xFFFFFF) != pointColor) { return false; } } return true; } private boolean checkRectangleAreaHasBeenFilledOnly(final BufferedImage baseRGBImage, final int fillColor, final int backgroundColor, final int areaLeftX, final int areaTopY, final int areaWidth, final int areaHeight) { final int areaRightX = areaLeftX + areaWidth; final int areaBottomY = areaTopY + areaHeight; final int imagewidth = baseRGBImage.getWidth(); final int imageheight = baseRGBImage.getHeight(); for (int y = 0; y < imageheight; y++) { for (int x = 0; x < imagewidth; x++) { final int rgb = baseRGBImage.getRGB(x, y) & 0xFFFFFF; final boolean notInArea = x < areaLeftX || x > areaRightX || y < areaTopY || y > areaBottomY; if (notInArea) { assertEquals("Must be background color "+backgroundColor, backgroundColor, rgb); } else { assertEquals("Must be fill color " + fillColor, fillColor, rgb); } } } return true; } @Test public void testFillTriangle_VisualTest() throws Exception { // the graphic log image file final File gfxLogFile = new File("./testimage.png"); // create a RGB memory rendered image which will be our base for the test final BufferedImage baseTestImage = new BufferedImage(200, 200, BufferedImage.TYPE_INT_RGB); final Graphics2D gfx = (Graphics2D) baseTestImage.getGraphics(); // we must disable antialasing for the graphics to avoid artefacts ((Graphics2D) gfx).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); final int backColor = 0x000000; final int shapeColor = 0xFFFFFF; // fill the image by our background color gfx.setColor(new Color(backColor)); gfx.clearRect(0, 0, 200, 200); // set the shape color gfx.setColor(new Color(shapeColor)); // our triangles, we use non-equaterial triangles, to make a rectangle, not a square final int[] firstTriangleX = new int[]{10, 10, 50}; final int[] firstTriangleY = new int[]{10, 150, 150}; final int[] secondTriangleX = new int[]{10, 50, 50}; final int[] secondTriangleY = new int[]{10, 10, 150}; // draw the first triangle TriangleFiller.fillTriangle(gfx, firstTriangleX, firstTriangleY); // save the current graphic state as an image (like log) ImageIO.write(baseTestImage, "png", gfxLogFile); assertTrue("The image must have set the points of vertices", checkTriangleCornerPoints(baseTestImage, shapeColor, firstTriangleX, firstTriangleY)); // draw the second triangle, to get a filled rectangular area on the image TriangleFiller.fillTriangle(gfx, secondTriangleX, secondTriangleY); gfx.dispose(); // save the current graphic state as an image (like log) ImageIO.write(baseTestImage, "png", gfxLogFile); assertTrue("Only the rectangle area must be filled, without artefacts",checkRectangleAreaHasBeenFilledOnly(baseTestImage, shapeColor, backColor, 10, 10, 40, 140)); } }