Java 8 + Swing: How to Draw Flush Polygons -



Java 8 + Swing: How to Draw Flush Polygons -

(sorry long post... @ to the lowest degree has pictures?)

i have written algorithm creates mosaic image statistically generating n convex polygons cover image no overlap. these polygons have anywhere between 3-8 sides, , each side has angle multiple of 45 degrees. these polygons stored internally rectangle displacements each corner. below image explains how works:

getright() returns x + width - 1, , getbottom() returns y + height - 1. class designed maintain tight bounding box around filled pixels coordinates shown in image correct. note width >= ul + ur + 1, width >= ll + lr + 1, height >= ul + ll + 1, , height >= ur + ul + 1, or there empty pixels on side. note possible corner's displacement 0, indicating pixels filled in corner. enables representation store 3-8 sided convex polygons, each of sides @ to the lowest degree 1 pixel in length.

while it's nice mathematically represent these regions, want draw them can see them. using simple lambda , method iterates on each pixel in polygon, can render image perfectly. example, below claude monet's woman parasol using 99 polygons allowing split directions.

the code renders image looks this:

public void drawonto(graphics graphics) { graphics.setcolor(getcolor()); foreach( (i, j) -> { graphics.fillrect(x + i, y + j, 1, 1); } ); } private void foreach(perpixel algorithm) { (int j = 0; j < height; ++j) { int nj = height - 1 - j; int minx; if (j < ul) { minx = ul - j; } else if (nj < ll) { minx = ll - nj; } else { minx = 0; } int maxx = width; if (j < ur) { maxx -= ur - j; } else if (nj < lr) { maxx -= lr - nj; } (int = minx; < maxx; ++i) { algorithm.perform(i, j); } } }

however, not ideal many reasons. first, concept of graphically representing polygon part of class itself; improve allow other classes focus represent these polygons. second, entails many, many calls fillrect() draw single pixel. finally, want able develop other methods of rendering these polygons drawing them as-is (for example, performing weighted interpolation on voronoi tessellation represented polygons' centers).

all of these point generating java.awt.polygon represents vertices of polygon (which named region differentiate polygon class). no problem; wrote method generate polygon has corners above no duplicates handle cases displacement 0 or side has 1 pixel on it:

public polygon getpolygon() { int[] xes = { x + ul, getright() - ur, getright(), getright(), getright() - lr, x + ll, x, x }; int[] yes = { y, y, y + ur, getbottom() - lr, getbottom(), getbottom(), getbottom() - ll, y + ul }; int[] keptxes = new int[8]; int[] keptyes = new int[8]; int length = 0; (int = 0; < 8; ++i) { if ( length == 0 || keptxes[length - 1] != xes[i] || keptyes[length - 1] != yes[i] ) { keptxes[length] = xes[i]; keptyes[length] = yes[i]; length++; } } homecoming new polygon(keptxes, keptyes, length); }

the problem that, when seek utilize such polygon graphics.fillpolygon() method, not fill of pixels! below same mosaic rendered different method:

so have few related questions behavior:

why polygon class not fill in these pixels, though angles simple multiples of 45 degrees?

how can consistently code around defect (as far application concerned) in renderers can utilize getpolygon() method as-is? not want alter vertices outputs because need them precise center-of-mass calculations.

mce

if above code snippets , pictures not plenty help explain problem, have added minimal, complete, , verifiable illustration demonstrates behavior described above.

package com.sadakatsu.mce; import java.awt.color; import java.awt.graphics; import java.awt.polygon; import java.awt.image.bufferedimage; import java.io.file; import java.io.ioexception; import javax.imageio.imageio; public class main { @functionalinterface private static interface perpixel { void perform(int x, int y); } private static class part { private int height; private int ll; private int lr; private int width; private int ul; private int ur; private int x; private int y; public region( int x, int y, int width, int height, int ul, int ur, int ll, int lr ) { if ( width < 0 || width <= ll + lr || width <= ul + ur || height < 0 || height <= ul + ll || height <= ur + lr || ul < 0 || ur < 0 || ll < 0 || lr < 0 ) { throw new illegalargumentexception(); } this.height = height; this.ll = ll; this.lr = lr; this.width = width; this.ul = ul; this.ur = ur; this.x = x; this.y = y; } public color getcolor() { homecoming color.black; } public int getbottom() { homecoming y + height - 1; } public int getright() { homecoming x + width - 1; } public polygon getpolygon() { int[] xes = { x + ul, getright() - ur, getright(), getright(), getright() - lr, x + ll, x, x }; int[] yes = { y, y, y + ur, getbottom() - lr, getbottom(), getbottom(), getbottom() - ll, y + ul }; int[] keptxes = new int[8]; int[] keptyes = new int[8]; int length = 0; (int = 0; < 8; ++i) { if ( length == 0 || keptxes[length - 1] != xes[i] || keptyes[length - 1] != yes[i] ) { keptxes[length] = xes[i]; keptyes[length] = yes[i]; length++; } } homecoming new polygon(keptxes, keptyes, length); } public void drawonto(graphics graphics) { graphics.setcolor(getcolor()); foreach( (i, j) -> { graphics.fillrect(x + i, y + j, 1, 1); } ); } private void foreach(perpixel algorithm) { (int j = 0; j < height; ++j) { int nj = height - 1 - j; int minx; if (j < ul) { minx = ul - j; } else if (nj < ll) { minx = ll - nj; } else { minx = 0; } int maxx = width; if (j < ur) { maxx -= ur - j; } else if (nj < lr) { maxx -= lr - nj; } (int = minx; < maxx; ++i) { algorithm.perform(i, j); } } } } public static void main(string[] args) throws ioexception { int width = 10; int height = 8; part region = new region(0, 0, 10, 8, 2, 3, 4, 1); bufferedimage image = new bufferedimage( width, height, bufferedimage.type_3byte_bgr ); graphics graphics = image.getgraphics(); graphics.setcolor(color.white); graphics.fillrect(0, 0, width, height); region.drawonto(graphics); imageio.write(image, "png", new file("expected.png")); image = new bufferedimage( width, height, bufferedimage.type_3byte_bgr ); graphics = image.getgraphics(); graphics.setcolor(color.white); graphics.fillrect(0, 0, width, height); graphics.setcolor(color.black); graphics.fillpolygon(region.getpolygon()); imageio.write(image, "png", new file("got.png")); } }

i spent day working on it, , seem have prepare this. clue found in documentation shape class, reads:

definition of insideness: point considered lie within shape if , if:

it lies within theshape boundary or

it lies on shape boundary , space adjacent point in increasing x direction exclusively within boundary or

it lies on horizontal boundary segment , space adjacent point in increasing y direction within boundary.

actually, text bit misleading; 3rd case overrides sec (i.e., if pixel in horizontal boundary segment on bottom of shape has filled point right, still not filled). represented pictorially, polygon below not draw x'ed out pixels:

the red, green, , bluish pixels part of polygon; rest not. bluish pixels fall under first case, greenish pixels fall under sec case, , reddish pixels fall under 3rd case. note of rightmost , lowest pixels along convex hull not drawn. them drawn, have move vertices orange pixels shown create new rightmost/bottom-most portion of convex hull.

the easiest way utilize camickr's method: utilize both fillpolygon() , drawpolygon(). @ to the lowest degree in case of 45-degree-multiple-edged convex hulls, drawpolygon() draws lines vertices (and other cases well), , fill pixels fillpolygon() misses. however, neither fillpolygon() nor drawpolygon() draw single-pixel polygon, 1 has code special case handle that.

the actual solution developed in trying understand insideness definition above create different polygon modified corners shown in picture. has benefit (?) of calling drawing library 1 time , automatically handles special case. not optimal, here code used anyone's consideration:

package com.sadakatsu.mosaic.renderer; import java.awt.polygon; import java.util.arrays; import com.sadakatsu.mosaic.region; public class regionpolygon extends polygon { public regionpolygon(region region) { int bottom = region.getbottom(); int ll = region.getll(); int lr = region.getlr(); int right = region.getright(); int ul = region.getul(); int ur = region.getur(); int x = region.getx(); int y = region.gety(); int[] xes = { x + ul, right - ur + 1, right + 1, right + 1, right - lr, x + ll + 1, x, x }; int[] yes = { y, y, y + ur, bottom - lr, bottom + 1, bottom + 1, bottom - ll, y + ul }; npoints = 0; xpoints = new int[xes.length]; ypoints = new int[xes.length]; (int = 0; < xes.length; ++i) { if ( == 0 || xpoints[npoints - 1] != xes[i] || ypoints[npoints - 1] != yes[i] ) { addpoint(xes[i], yes[i]); } } } }

java swing polygon

Comments

Popular posts from this blog

formatting - SAS SQL Datepart function returning odd values -

c++ - Apple Mach-O Linker Error(Duplicate Symbols For Architecture armv7) -

php - Yii 2: Unable to find a class into the extension 'yii2-admin' -