0

I'm getting a really strange behavior/issue in Java. What I'm doing boils down to drawing simple shapes onto a canvas. Everything was going just fine until I decided to add another thread that can access my canvas.

So there are two threads, each draw similar shapes and each rely on the same functions (in another non-thread object) to do the drawing. These functions have been made synchronous to protect the underlying draw commands from getting called out of sequence.

Everything works great, except when I set the color of thread #2's drawing function call to include an alpha channel. When I do I get the following exception:

Exception in thread "Thread-3" java.awt.geom.IllegalPathStateException: missing initial moveto in path definition
    at java.awt.geom.Path2D$Float.needRoom(Unknown Source)
    at java.awt.geom.Path2D.closePath(Unknown Source)
    at sun.java2d.pipe.PixelToShapeConverter.makePoly(Unknown Source)
    at sun.java2d.pipe.PixelToShapeConverter.fillPolygon(Unknown Source)
    at sun.java2d.pipe.ValidatePipe.fillPolygon(Unknown Source)
    at sun.java2d.SunGraphics2D.fillPolygon(Unknown Source)
    at java.awt.Graphics.fillPolygon(Unknown Source)
    at com.deadbird.zndo.Tile.drawPolygon(Tile.java:177)
    at com.deadbird.zndo.TiledImage.drawPolygon(TiledImage.java:158)
    at com.deadbird.zndo.TileSet.drawPolygon(TileSet.java:46)
    at com.deadbird.zndo.Map.drawPolygonAtCoords(Map.java:90)
    at com.deadbird.zndo.CutterThread.drawArea(CutterThread.java:146)
    at com.deadbird.zndo.CutterThread.flushTmpAreaList(CutterThread.java:107)
    at com.deadbird.zndo.CutterThread.cut(CutterThread.java:68)
    at com.deadbird.zndo.CutterThread.run(CutterThread.java:50)
    at java.lang.Thread.run(Unknown Source)

What kills me is that this error seems to indicate that something is wrong with the geometry I am feeding it, I KNOW THIS TO NOT BE TRUE, when I run the same code, same geometry, just with a color object that does not include an alpha value the program happily runs just fine, chugging a lot of data with ease and the drawing functions show no signs of having issues with the two threads at all.

It's also worth noting that thread #1 has no problem calling the same draw function with an alpha value in the color object, those results draw just fine.

So my question is, what could cause this discrepancy? Same function, two threads, one draws just fine with alpha and non-alpha colors, the other only seems to work with a non-alpha.

This is the function in question:

public synchronized void drawPolygon(double[] x, double[] y, Color color) {

    // Create polygon
    int[] intX = new int[x.length];
    int[] intY = new int[y.length];

    // Convert the double array to an int array
    for (int i=0; i < intX.length; i++) {
        intX[i] = (int) x[i]; 
        intY[i] = (int) y[i]; 
    }

    Polygon poly = new Polygon(intX, intY, intX.length);

    // Now draw that poly
    g.setColor(color);
    g.fillPolygon(poly);

}

Being more specific about what causes the issue, this works:

drawPolygon(x, y, new Color(13, 191, 0) );

This does not...

drawPolygon(x, y, new Color(13, 191, 0, 30) );

It's interesting because I'm not feeding this a shape object, I'm giving it a static set of X and Y values and letting Java assemble them into a polygon object. Whatever path-forming is done, it should all be handled correctly by the Polygon's object (and it's worked just fine until I introduced the new thread, which I don't believe is the issue here).

This really looks like an internal issue somehow, any thoughts?

-Cody

Cody Smith
  • 2,732
  • 3
  • 31
  • 43
  • Where did you learn that it was safe to use the same graphics context concurrently? – obataku Sep 15 '12 at 23:28
  • Which line of code causes your problem? Are you taking care to only make this type of call on the one event thread? – Hovercraft Full Of Eels Sep 15 '12 at 23:28
  • At the risk of asking an extremely dumb question, why is reusing the graphics context a bad thing? It's worth noting that all drawing is being done to a BufferedImage, which is then being drawn to my canvas. – Cody Smith Sep 15 '12 at 23:34
  • I have my regular thread (I'll call it main) which creates the canvas, and two task threads - both of which call the draw function of my canvas object. I assume that the canvas object is utilizing the event thread, however I will admit that I do not completely understand the process. – Cody Smith Sep 15 '12 at 23:38
  • Oh wow, I get it. Reusing a graphics context might be OK, but in a concurrent situation that's obviously not a good idea. Let me rewrite this function to create a new graphics context each time and see what happens. – Cody Smith Sep 15 '12 at 23:43
  • For better help sooner, post an [SSCCE](http://sscce.org/). – Andrew Thompson Sep 16 '12 at 01:52

1 Answers1

0

OK so I figured it out.

I was trying to draw an Area (java.awt.geom.Area) by breaking it down with a line iterator in my "Cut" thread (the thread causing issues). The CORRECT way of drawing an Area is to use Graphics2D's fill method instead of fillPolygon. Fill can draw any shape object including an Area.

-Cody

Cody Smith
  • 2,732
  • 3
  • 31
  • 43