« GalaxyGoo on Zazzle | Main | Happy Sputnik Day! »

Shapes unexpectedly cancelling each other out in AS3

This weekend, I was playing around with some AS1 code that Edwin posted a few years back. I even managed to convert it to AS3. Which was a great exercise!

His original version draws short lines, to fill a color pattern. In my simple modification, I've used graphics.drawEllipse() instead. But I keep getting a white line down the middle of the pattern, that shouldn't be there.

vLine2.gif vLine1.gif

When zooming in on the swf, I noticed that when dots overlap on the mid-line, they cancel each other and leave a white space. Very odd!

Wondering if the size of the shape would have any effect, I changed the width and height of the ellipses on half of the pattern.

vLine2b.gif vLine2a.gif

While this didn't give me the hoped-for result, it did give me an idea for simulating fish scales!

I'm sure I've seen something like this posted somewhere, but I just can't remember where or if there was a fix.


Update:

If I replace
...
var fillColor = f0*(sqX=x1*x1)+f1*sqX*sqX+f2*sqX*(sqY=y1*y1)+f3*sqY*sqY+f4*sqY;
c.graphics.beginFill(fillColor);
c.graphics.drawEllipse(pX=100-(x1-=2), pY=y1+100, 1.8,1.9);
c.graphics.drawEllipse(199-pX, pY,4,4);
c.graphics.drawEllipse(pX,198-pY,1.8,1.9);
c.graphics.drawEllipse(199-pX, 198-pY,3,3);
...

with

...
var fillColor = f0*(sqX=x1*x1)+f1*sqX*sqX+f2*sqX*(sqY=y1*y1)+f3*sqY*sqY+f4*sqY;
c.graphics.beginFill(fillColor);
c.graphics.drawEllipse(pX=100-(x1-=2), pY=y1+100, 1.8,1.9);
c.graphics.beginFill(fillColor);
c.graphics.drawEllipse(199-pX, pY,4,4);
c.graphics.beginFill(fillColor);
c.graphics.drawEllipse(pX,198-pY,1.8,1.9);
c.graphics.beginFill(fillColor);
c.graphics.drawEllipse(199-pX, 198-pY,3,3);
...

which simply adds a new beginFill command, before each drawEllipse command,

the subtraction problem is eliminated. Very strange.
vLine3.gif

Update (after Robert Penner's commentt):
vLine4.gif

Comments

This same behavior is seen in AS2. If you do not end your fill or start a new fill, any additional lines drawn will be considered as contours of the previous shape. Overlapping contours will cause whitespace between the lines of those contours.

funny, I never ran into this before.

It doesn't seem like a good behavior. The shapes should cover each other, and not cause a subtraction.

I wanted to start a fill, draw several dots, and end the fill. Saving several lines of instructions that repeat.

Hi Kristin,
It looks like the "cancelling" occurs only when the two ellipses are the same color. I'm pretty sure this is a result of Flash's "even-odd fill rule." Basically, when the path of a filled shape crosses over itself, the intersection region becomes a hole. In your case, if you don't separate the fills of the ellipses, Flash considers them the same shape if they're the same color. You should be calling beginFill() and endFill() for each ellipse for predictable results.

Illustrator lets you choose whether or not to use this fill rule:
http://livedocs.adobe.com/en_US/Illustrator/13.0/help.html?content=WS714a382cdf7d304e7e07d0100196cbc5f-644e.html

SVG also has the choice, with a technical explanation involving "rays" and infinity:

evenodd
This rule determines the "insideness" of a point on the canvas by drawing a ray from that point to infinity in any direction and counting the number of path segments from the given shape that the ray crosses. If this number is odd, the point is inside; if even, the point is outside.
http://www.w3.org/TR/SVG/painting.html#FillProperties

Robert, thanks!

I know this may seem simplistic, but I want the shapes I create with code to behave the same way as they do when I draw them with the Shape tool in the authoring environment. If I draw a new shape, with the same fill color, overlapping another...the shapes merge into one, yes? Why is there subtraction on overlap when generated from code, but not in authoring environment? I'm really trying to get a grasp on this.

I'm not sure if it's just that they are the same color. If I replace the code that assigns color, and set it so that all ellipses are the same color, there are no "subtractions" at all. I get a solid colored block, with subtractions only at the mid-lines.
I've added a screen shot of this at the end of the original post.

That's a reasonable expectation, but if the drawing API actually worked that way, it would actually take away functionality.

It all comes down to donuts. Think about how you punch a hole in an object in Flash Authoring. There are a number of different ways. But how would you draw a donut with the drawing API? How would you tell Flash to subtract color instead of adding it?

Another exercise: draw a five-pointed star on stage using the pen tool, Zorro-style. How many nodes do you get? Notice how Flash adds nodes at the line intersections as you draw.

Bringing that to the drawing API isn't easy. If Flash Player were detecting intersections as you added lines, that would slow things down. A more basic limitation is that even if the Player added a "node" somewhere, there aren't APIs to move nodes around at runtime.

Thanks Robert, that makes a lot of sense now. Especially when you put it in terms of slowing down the player :-)

I may solve this particular case, with a test to see if it's on the last iterations, and use beginFill for each of these ellipses.

Now you have me daydreaming of node APIs!

Gratuitous Simpsons quotes:

"Mmmm... donuts."

[Coming out of the "Holes" IMAX documentary]
"Did you know that the hole's only natural enemy is the pile?"