Archive for November 2006


Mmm…Donuts

November 30th, 2006 — 1:33am

This has come up a couple times in the past couple months leading me to believe that there are others out there who might benefit from this. I’m overdue for an post anyways.

The question: How do you draw shapes with holes in them? (i.e. How do I draw a donut?)

Short answer: Winding rules.

So what’s a winding rule? A winding rule is a way to determine whether a point is inside or outside a shape, useful for when you want to fill a shape. Quartz (like Postscript) has two different winding rules: even-odd and non-zero.

Non-zero is the default. How does it work? Take the point in question. Follow a line from that point extending out to infinity. Now, maintain a count. Increment the count every time you cross the path with the path going from left to right. Decrement whenever you cross a path going from right to left. In the end, if the count is zero, you are outside the shape, otherwise you are inside.

nonzerowinding.png

In the diagram above, the final count is zero. Note that this is a compound path (remember, paths do not have to be contiguous). Our imaginary ray crosses the path twice but does so with the paths going in opposite directions. This means that the point in the middle of both circles is considered outside the shape. VoilĂ  , a donut.

With even-odd, it’s a bit simpler. Draw a line out from the point but just increment every time you cross the path (regardless of direction). If the resulting count is even, you are outside, otherwise you are inside.

Except for the labels on the axes, the pic below is actual output from a Cocoa program showing different combinations. The top two shapes have the outer and inner circles specified going in the same direction. The bottom two have the inner cirlce going in the opposite direction as the outer. The shapes on the left are drawn with non-zero winding while the two on the right are drawn with even-odd. Paths are stroked in white.

donuts.png

Notice how the direction of the paths does not matter for even-odd. Also notice how in the case of non-zero with the paths going in the same direction (top-left donut), the inner circle is considered a part of the shape’s interior. This shows that non-zero gives you more control (you can control what parts of the shape are considered inside by adjusting the direction of the paths). It is also more tedious to deal with for the more simple cases. To draw donuts using non-zero, I did the outer circle, created another path for the inner circle, reversed it and added it to the outer circle’s path. Using even-odd, all I had to do is set the winding rule on the path. For more complex cases, the control of non-zero winding may be required but for simple shapes like donuts, use even-odd. Why you’d ever want to draw anything else besides donuts is beyond me; donuts are delicious. While this knowledge can be applied to other less worthy shapes, I cannot be held responsible for the jeers you will undoubtedly receive for even daring to allow to cross one’s mind the slightest notion of contemplating considering drawing anything non-donut-like.

I’m too lazy busy to clean up the code for you to download but play with it yourself. It can all be done via NSBezierPath (key methods are -bezierPathByReversingPath and -setWindingRule:). Also, the winding rules can apply to clipping as indicated by the following pic:

donutclip.png

For extra credit, play with self-intersecting paths.

Enjoy.

Comment » | Cocoa, OS X, Programming, Quartz

Antisocial Software

November 7th, 2006 — 12:10am

Unless you installed your operating system from floppies, chances are that you have a bunch of programs running on your computer at any one time. There are enough things that can go wrong in any one particular program and when you add them into the same soup, the interactions between them create more scenarios where things can go awry. The operating system has ways of preventing programs from mucking with each other via protected memory and resource limits but it’s not that surprising when some program will interfere with another.

It’s something I have to deal with a lot with Hazel. Since Hazel runs in the background and manipulates files it does not have full control over, there’s a lot to be watch out for. I have to coordinate with browsers to make sure not to move the file while it’s still being downloaded. I try and detect when the user is copying something with the Finder (which for some reason uses ‘brok’ as the file type instead of the ‘bzy ‘ or ‘bzy?’ types which I believe was the convention from the older MacOS days). I run my background processes with lower priority and even use low priority IO. Try this test. Take a large file and copy it. Turn off Hazel’s trash management options, move one of the files to the trash and use Finder’s “Secure Empty Trash”. Observe how usable your machine is while this is happening (for me, the answer is “barely”). Now, turn on Hazel’s trash management, setting the trash size threshold to something lower than the file size. Set Hazel to throw away oversized files immediately and to do so securely. Now, throw away the other file. You can tell something is happening but at least from all my tests, my machine is more responsive.

So, it’s a bit frustrating when you go through the trouble of making your software a good citizen when someone else’s software goes out of their way to interfere with yours.

A while back, I got a report from a customer that Hazel was not working. Looking at the logs, the customer noticed that it would stop working whenever he ran Logic Pro. When he quit Logic, Hazel would magically work again. At first, I didn’t believe it. It seemed too weird but I downloaded a trial of Logic Express and sure enough, I experienced the exact same behavior. After a bit of poking around I discovered what was happening. Logic Pro/Express stops all launchd jobs. Hazel uses launchd to start its background processes so it was a bit disconcerting to see another program, especially one from Apple, disabling yours on purpose, albeit indirectly. At least Logic is nice enough to start the jobs again when it quits.

Now, I’m sure the Logic team is probably doing this to ensure a level of performance but scouring the Apple lists and the web at large turned up nothing about this behavior. Maybe a tech note somewhere would have been nice. It’s unclear if any of Apple’s other pro apps exhibit this behavior but at least now I know what to look for.

Should this be a preference in Logic? Maybe a warning when it detects that the user has their own launchd jobs? I know it’s not common for software out there to depend on launchd but it is pretty annoying for those of us it does affect. I could write my own daemon using kqueue (which launchd uses to monitor file changes). Logic will not interfere with it then, but part of me feels that this would make Hazel impolite. Logic is doing what it’s doing for a reason and to work around its intentions goes against Hazel’s good manners. So for the time being, I’ll just have to accept that the housekeeper must go on break whenever the cops come in to commandeer the house.

Comment » | Hazel, OS X, Programming

Back to top