<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Safe from the Losing Fight &#187; Programming</title>
	<atom:link href="http://losingfight.com/blog/category/programming/feed/" rel="self" type="application/rss+xml" />
	<link>http://losingfight.com/blog</link>
	<description>because i don&#039;t write software for windows</description>
	<lastBuildDate>Mon, 21 May 2012 20:37:29 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
	<atom:link rel='hub' href='http://losingfight.com/blog/?pushpress=hub'/>
		<item>
		<title>How to implement boolean operations on bezier paths, Part 3</title>
		<link>http://losingfight.com/blog/2011/07/09/how-to-implement-boolean-operations-on-bezier-paths-part-3/</link>
		<comments>http://losingfight.com/blog/2011/07/09/how-to-implement-boolean-operations-on-bezier-paths-part-3/#comments</comments>
		<pubDate>Sat, 09 Jul 2011 07:01:13 +0000</pubDate>
		<dc:creator>andy</dc:creator>
				<category><![CDATA[Graphics]]></category>
		<category><![CDATA[Macintosh]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://losingfight.com/blog/?p=496</guid>
		<description><![CDATA[Previously, I covered how to find the intersections between two bezier curves and gave a conceptual overview of how to perform boolean operations on bezier paths. In this final installment I&#8217;ll present the algorithm used to implement the boolean operations. Overview The algorithm that I show here is based on the algorithm presented in &#8220;Efficient [...]]]></description>
			<content:encoded><![CDATA[<p>Previously, I covered how to <a href="http://losingfight.com/blog/2011/07/06/how-to-implement-boolean-operations-on-bezier-paths-part-1/">find the intersections between two bezier curves</a> and gave a <a href="http://losingfight.com/blog/2011/07/07/how-to-implement-boolean-operations-on-bezier-paths-part-2/">conceptual overview of how to perform boolean operations on bezier paths</a>. In this final installment I&#8217;ll present the algorithm used to implement the boolean operations.</p>
<h2>Overview</h2>
<p>The algorithm that I show here is based on the algorithm presented in <a href="http://www.inf.usi.ch/hormann/papers/Greiner.1998.ECO.pdf">&#8220;Efficient clipping of arbitrary polygons&#8221; by Günther Greiner and Kai Hormann</a>. My algorithm is adapted to work on closed bezier paths (instead of polygons), handle nonintersecting (sub)paths, and handle intersections between fill paths and hole paths.</p>
<p>As before the <a href="https://bitbucket.org/andyfinnell/vectorboolean">full source code is available on Bitbucket</a>, and it&#8217;s licensed under the MIT license. If you want to follow along, the majority of the algorithms described are implemented in the FBBezierGraph class.</p>
<h2>Data Structures</h2>
<p>My algorithm, like Greiner-Hormann&#8217;s, uses several data structures. The primary is FBBezierGraph. Think of FBBezierGraph as an expanded version of NSBezierPath that can be annotated with where intersections happen. FBBezierGraph contains FBBezierContours, which are just closed subpaths. Anytime I see a moveto in a NSBezierPath, that&#8217;s a new contour. FBBezierContours in turn contain FBContourEdges, which are mainly wrappers around a FBBezierCurve. They represent one cubic bezier curve, and can also hold FBEdgeCrossings. Each FBEdgeCrossing represents a location where another edge crosses this edge.</p>
<p>By breaking a NSBezierPath out into all these separate structures, it makes it easier to process. Contours need to be dealt with one at a time, and I need a way to keep track of where the intersections happen. The basic flow is to convert my NSBezierPath into a FBBezierGraph, perform the boolean operation, then convert it back to a NSBezierPath. FBBezierGraph handles both sides of the conversion.</p>
<h2>Basic Algorithm</h2>
<p>The basic algorithm for union, intersect, and difference are very similar. In fact, there&#8217;s only one step that&#8217;s all that different between the three. The basic steps are:</p>
<ol>
<li>
<p>Find all the intersections where the edges actually cross, and insert FBEdgeCrossings into  both FBBezierGraphs at those locations.</p>
</li>
<li>
<p>Handle all the intersecting contours.</p>
<ul>
<li>
<p>Walk each contour and mark the entry and exit into the section I want to output to the final result.</p>
</li>
<li>
<p>Walk each contour and output the final contours by following the entry and exit directions marked in the previous step.</p>
</li>
</ul>
</li>
<li>
<p>Handle all the nonintersecting contours.</p>
</li>
</ol>
<p>Step three is the only step that is very different between the operations. Step two is identical except for if we mark the inside or outside section.</p>
<p>The above algorithm only applies to union, intersect, and difference. On the other hand, the entire implementation for exclusive or is:</p>
<p><code></p>
<pre>
- (FBBezierGraph *) xorWithBezierGraph:(FBBezierGraph *)graph
{
    FBBezierGraph *allParts = [self unionWithBezierGraph:graph];
    FBBezierGraph *intersectingParts = [self intersectWithBezierGraph:graph];
    return [allParts differenceWithBezierGraph:intersectingParts];
}
</pre>
<p></code></p>
<p>As I&#8217;ve mentioned previously, exclusive or is implemented in terms of union, intersect and difference. I&#8217;ll now ignore exclusive or for the rest of the post.</p>
<h2>Finding Crossings</h2>
<p>For all three operations I start the same way: finding all the intersections where the edges cross. I do this by simply walking each edge of the subject bezier graph and intersecting them with the edges of the clipping graph. I don&#8217;t look for self intersections. I insert a FBEdgeCrossing into each bezier graph for each intersection, and point the crossings at each other so I can easily jump between graphs at crossings. You can find the code for this in the insertCrossingsWithBezierGraph: method.</p>
<p>There are a couple of things I have to look out for when determining if two edges actually cross at an intersection. One possibility is that the two edges are tangent at the intersection, and don&#8217;t cross. That is straightforward to detect; I compute the tangent for both curves at the intersection point, and see if they&#8217;re parallel. If they are, then they are tangent at that point.</p>
<p>The more involved case is when the intersection happens at the end point of one or both of the edges. If an intersection happens in the interior of two curves, and it&#8217;s not tangent, then I know the edges actually cross. But suppose I encounter the following intersection:</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/07/CrossingAtEnd1.png" alt="CrossingAtEnd" border="0" width="500" height="250" /></p>
<p>I don&#8217;t know if the two contours cross or not just by looking at these two edges alone. I need to look at the next edge. There are two basic possibilities:</p>
<table>
<tr>
<td>
<img src="http://losingfight.com/blog/wp-content/uploads/2011/07/CrossingThatCross.png" alt="CrossingThatCross" border="0" width="500" height="250" />
</td>
<td>
<img src="http://losingfight.com/blog/wp-content/uploads/2011/07/CrossingThatDontCross1.png" alt="CrossingThatDontCross" border="0" width="500" height="250" />
</td>
</tr>
</table>
<p>Either the contours cross at the intersection, or they don&#8217;t (I consider going coincident to be not crossing). I use the tangents at the intersection point to determine if the contours actually cross or not. The tangents for the above examples look something like:</p>
<table>
<tr>
<td>
<img src="http://losingfight.com/blog/wp-content/uploads/2011/07/CrossingTangentsCross.png" alt="CrossingTangentsCross" border="0" width="500" height="250" />
</td>
<td>
<img src="http://losingfight.com/blog/wp-content/uploads/2011/07/CrossingTangentsDontCross.png" alt="CrossingTangentsDontCross" border="0" width="500" height="250" />
</td>
</tr>
</table>
<p>I then compute the angles of the tangents by computing the polar coordinates. If the contours cross, the angles will cross as well. The method doesEdge:crossEdge:atIntersection: implements the crossing check.</p>
<p>When finding crossings I have to be wary of one additional problem caused by intersections at end points. Since the end of one edge is the start of the next, an intersection at the end point will be found on both edges, resulting in duplicate crossings. So when I&#8217;m done finding all the crossings, I&#8217;ll go through the crossings I found and remove the duplicates.</p>
<h2>Intersecting Contours</h2>
<p>I take the processing of intersecting contours in two steps: marking which sections (inside or outside) of each contour to output, and then creating a new bezier graph containing those sections. The code for doing this for all three boolean operations is:</p>
<p><code></p>
<pre>
    [self markCrossingsAsEntryOrExitWithBezierGraph:graph markInside:NO];
    [graph markCrossingsAsEntryOrExitWithBezierGraph:self markInside:NO];

    FBBezierGraph *result = [self bezierGraphFromIntersections];
</pre>
<p></code></p>
<p>This is the code from the union operation. The code for the intersect and difference operations are identical except for the values passed in to the markInside parameter. Intersect passes YES for both self and graph, while difference passes NO for self and YES for graph (marking the outside of self and inside of graph).</p>
<p>When I mark the crossings as entry or exit, I go one contour at a time and mark the entries and exits relative to the other contour crossing it:</p>
<p><code></p>
<pre>
- (void) markCrossingsAsEntryOrExitWithBezierGraph:(FBBezierGraph *)otherGraph markInside:(BOOL)markInside
{
    for (FBBezierContour *contour in self.contours) {
        NSArray *intersectingContours = contour.intersectingContours;
        for (FBBezierContour *otherContour in intersectingContours) {
            if ( otherContour.inside == FBContourInsideHole )
                [contour markCrossingsAsEntryOrExitWithContour:otherContour markInside:!markInside];
            else
                [contour markCrossingsAsEntryOrExitWithContour:otherContour markInside:markInside];
        }
    }
}
</pre>
<p></code></p>
<p>Above I check to see if the other contour I&#8217;m intersecting with is a hole or not. As I talked about in the previous post, if the other contour is a hole, then I want to mark the opposite section that I normally would for this operation.</p>
<p>The method markCrossingsAsEntryOrExitWithContour:markInside: does the actual marking of crossings as entry or exit. The pseudocode for marking entries and exists:</p>
<ol>
<li>
<p>I pick a point on the contour to start with.</p>
</li>
<li>
<p>I determine if the point lies inside or outside the other contour, using the even odd rule.</p>
</li>
<li>
<p>Using the markInside parameter and if the start point is inside or outside, I determine if the start point is in the section I want to output or not.</p>
<ol>
<li>
<p>If the start point is in the right section already, the next crossing will be an exit, so assign isNextCrossingAnEntry = NO.</p>
</li>
<li>
<p>If the start point is not in the section I want to output, the next crossing will be an entry, so  I assign isNextCrossingAnEntry = YES.</p>
</li>
</ol>
</li>
<li>
<p>For each crossing on the contour (starting with my start point and proceeding in order):</p>
<ol>
<li>
<p>Assign the crossing&#8217;s property isEntry = isNextCrossingAnEntry.</p>
</li>
<li>
<p>Toggle the value of isNextCrossingAnEntry.</p>
</li>
</ol>
</li>
</ol>
<p>The only tricky part of this is choosing a good start point. I don&#8217;t want a start point that is ambiguous, like one that is on the other contour.</p>
<p>After I&#8217;m done marking all the crossings as entry or exit, I need to build the final contours. The algorithm for that is:</p>
<ol>
<li>
<p>While there are unprocessed crossings do:</p>
<ol>
<li>
<p>I find the first unprocessed crossing on the bezier graph.</p>
</li>
<li>
<p>I create a new contour.</p>
</li>
<li>
<p>While the current crossing hasn&#8217;t be processed do:</p>
<ol>
<li>
<p>If the crossing is an entry, I move forward through the contour adding the edges (or edge segment if there&#8217;s a crossing) until I encounter the next crossing.</p>
</li>
<li>
<p>Else the crossing is an exit, and I move backwards through the contour, adding edges (or segments) until I encounter the next crossing.</p>
</li>
<li>
<p>I switch to the other bezier graph by setting the current crossing to it&#8217;s counterpart.</p>
</li>
</ol>
</li>
<li>
<p>I add the new contour to the final bezier graph.</p>
</li>
</ol>
</li>
</ol>
<p>And now I&#8217;m done processing all the intersecting contours.</p>
<h2>Nonintersecting Contours</h2>
<p>The final part of a boolean operation is dealing with the nonintersecting contours. This is where the various boolean operations differ the most. I start with the list of contours that don&#8217;t intersect anything.</p>
<p>For the union operation, I start out optimistically and assume they&#8217;ll all end up in the final result. I then walk both bezier graph&#8217;s nonintersecting contours and see if an individual contour is inside (as defined by the even odd rule) the opposite bezier graph. If it is, I know it&#8217;s redundant and I remove it from the final contours.</p>
<p>The code looks something like:</p>
<p><code></p>
<pre>
    for (FBBezierContour *ourContour in ourNonintersectingContours) {
        if ( [graph containsContour:ourContour] )
            [finalNonintersectingContours removeObject:ourContour];
    }
    for (FBBezierContour *theirContour in theirNonintersectinContours) {
        if ( [self containsContour:theirContour] )
            [finalNonintersectingContours removeObject:theirContour];
    }
</pre>
<p></code></p>
<p>Intersect is more or less the opposite of union. I start by assuming none of the nonintersecting contours from either bezier graph will make it. I then walk all the nonintersecting contours and see if the opposite bezier graph contains them. If the opposite graph does, then there is overlap, and the overlap is the contour being contained.</p>
<p>A simplified version of the code for intersect is:</p>
<p><code></p>
<pre>
    for (FBBezierContour *ourContour in ourNonintersectingContours) {
        if ( graph containsContour:ourContour] )
            [finalNonintersectingContours addObject:ourContour];
    }
    for (FBBezierContour *theirContour in theirNonintersectinContours) {
        if ( [self containsContour:theirContour] )
            [finalNonintersectingContours addObject:theirContour];
    }
</pre>
<p></code></p>
<p>I start computing the difference for nonintersecting contours by assuming none will make it into the final result. I then walk the nonintersecting contours for the subject bezier graph. If they are not contained by (and thus not subtracted away) the clipping bezier graph, I add them to the final contours. Next I walk the nonintersecting contours for the clipping bezier graph. If they are contained by the subject bezier graph, that means they cut a hole in the subject, so I add them to final contours.</p>
<p>The code looks kind of like:</p>
<p><code></p>
<pre>
    for (FBBezierContour *ourContour in ourNonintersectingContours) {
        if ( ![graph containsContour:ourContour] )
            [finalNonintersectingContours addObject:ourContour];
    }
    for (FBBezierContour *theirContour in theirNonintersectinContours) {
        if ( [self containsContour:theirContour] )
            [finalNonintersectingContours addObject:theirContour]; // add it as a hole
    }
</pre>
<p></code></p>
<p>And with that I&#8217;m done. I have the final intersecting and nonintersecting contours and can convert the bezier graph back into a NSBezierPath.</p>
<h2>Contour Containment Issues</h2>
<p>In the previous section, I skipped over the implementation of the containsContour: method despite the fact it gave me fits in practice. In theory it should be easy to implement: I pick a point on the contour and use the even odd rule to see if the point is inside the other bezier graph or not. Unfortunately there are two situations which make it not as simple as I&#8217;d hoped.</p>
<p>The first problem is easiest seen:</p>
<table>
<tr>
<td>
<img src="http://losingfight.com/blog/wp-content/uploads/2011/07/ContainmentInside.png" alt="ContainmentInside" border="0" width="500" height="250" />
</td>
<td>
<img src="http://losingfight.com/blog/wp-content/uploads/2011/07/ContainmentOutside.png" alt="ContainmentOutside" border="0" width="500" height="250" />
</td>
</tr>
</table>
<p>Does the blue contour contain the red? In both cases the even odd rule returns one intersection, indicating that it does. However, just by looking at it, I can tell that in the diagram on the right, it doesn&#8217;t. The problem is the ray passes through an edge where both contours coincide. </p>
<p>The second problem is show below:</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/07/ContainmentSplit.png" alt="ContainmentSplit" border="0" width="500" height="250" /></p>
<p>This one is a bit more subtle. Notice that the ray I&#8217;m using to determine even or odd intersects where two edges meet. This means I&#8217;ll find two intersections (one for each edge) instead of just one, and I&#8217;ll think the red square is outside the blue circle.</p>
<p>My solution is somewhat brute force. I actually ended up casting a full line through the entire contour, instead of just one side, in order to increase my chances of getting a useful ray. I also alternate between horizontal and vertical lines, and I loop until I get a line that is unambiguous. There is more code dedicated to this operation that I like. There is probably a better way to do this.</p>
<h2>Conclusion</h2>
<p>I took on this project mainly for my own benefit, so I could learn how this works. But hopefully you&#8217;ve learned something useful too amidst all my struggling with this.</p>
<p>I have tried to test the sample code the best I could. You can check out all the test cases under the &#8220;Shapes&#8221; menu in the sample application. However, I&#8217;ve undoubtedly missed or left out edge cases which will cause the code to fail. If you decide to use this code in a commercial application: test, test, test. If you do find a case my code doesn&#8217;t handle, I&#8217;d like to hear about. That said, the code is provided as is, and I&#8217;m not guaranteeing any support for it.</p>
]]></content:encoded>
			<wfw:commentRss>http://losingfight.com/blog/2011/07/09/how-to-implement-boolean-operations-on-bezier-paths-part-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to implement boolean operations on bezier paths, Part 2</title>
		<link>http://losingfight.com/blog/2011/07/07/how-to-implement-boolean-operations-on-bezier-paths-part-2/</link>
		<comments>http://losingfight.com/blog/2011/07/07/how-to-implement-boolean-operations-on-bezier-paths-part-2/#comments</comments>
		<pubDate>Fri, 08 Jul 2011 02:52:09 +0000</pubDate>
		<dc:creator>andy</dc:creator>
				<category><![CDATA[Graphics]]></category>
		<category><![CDATA[Macintosh]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://losingfight.com/blog/?p=484</guid>
		<description><![CDATA[In my last post I showed how to find the intersection points between two bezier curves. While interesting, it&#8217;s merely a stop on the way to implementing boolean operations for bezier paths. This time I&#8217;ll show how to conceptually perform the four common boolean operations: union, intersect, difference, and exclusive or. I&#8217;ll cover the actual [...]]]></description>
			<content:encoded><![CDATA[<p>In my last post I showed <a href="http://losingfight.com/blog/2011/07/06/how-to-implement-boolean-operations-on-bezier-paths-part-1/">how to find the intersection points between two bezier curves</a>. While interesting, it&#8217;s merely a stop on the way to implementing boolean operations for bezier paths. This time I&#8217;ll show how to conceptually perform the four common boolean operations: union, intersect, difference, and exclusive or. I&#8217;ll cover the actual algorithms for implementing the four operations in the next post.</p>
<h2>Conceptually Speaking</h2>
<p>I think it&#8217;s helpful to start out with a simple case and see how this will work conceptually. I&#8217;ll start with the following example:</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/07/RectangleCircleIntersections.png" alt="RectangleCircleIntersections" border="0" width="507" height="413" /></p>
<p>Here I have a rectangle and circle overlapping. The intersections have already been calculated and circled in green. Now I consider the shapes as wireframes:</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/07/RectangleCircleWireframe.png" alt="RectangleCircleWireframe" border="0" width="507" height="413" /></p>
<p>In my head, I divide up each path into sections based on the intersection points. There are two kinds of sections: one that is outside the other path, and one that is inside the other path. Performing a boolean operation is just a matter of picking the correct section from each path.</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/07/WireframeSections.png" alt="WireframeSections" border="0" width="507" height="413" /></p>
<p>Here I&#8217;ve used a dashed style to mark which parts of the path are inside of the other path. Once I&#8217;ve separated the paths into the inside and outside parts, it&#8217;s easy to perform the boolean operations conceptually.</p>
<p>A union is a logical or, so I want all the outside sections:</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/07/WireframeUnion.png" alt="WireframeUnion" border="0" width="507" height="413" /></p>
<p>The intersect operation is a logical and, so I just want the inside sections:</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/07/WireframeIntersect.png" alt="WireframeIntersect" border="0" width="507" height="413" /></p>
<p>Difference is where I take a path and remove the parts that intersect with the other path. For that I want the outside sections of the subject (the rectangle), and the inside sections of the clip (the circle):</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/07/WireframeSubtract.png" alt="WireframeSubtract" border="0" width="507" height="413" /></p>
<p>For now I&#8217;m going to ignore logical exclusive or because it requires properly handling subpaths and holes, which I&#8217;m not ready to talk about just yet. However I will say that exclusive or isn&#8217;t a primitive like the other operations, but is defined in terms of union, intersect, and difference. Specifically A Xor B is defined as (A Union B) Difference (A Intersect B).</p>
<h2>Where is inside?</h2>
<p>Before I go any further, I need to define what it means for a point or path to be &#8220;inside&#8221; of another. The previous examples were simple and just by eyeing them I could tell if a point or path section was inside or not. However, I&#8217;ll need something more robust for more complex operations.</p>
<p>Traditionally there are two ways to determine if a given point is inside a closed path or not. First, there&#8217;s the winding rule. I count how many times the path winds around the given point. If it&#8217;s more than 0, then the point is inside the path. This is default way NSBezierPath determines if a point is inside a path or not.</p>
<p>The second way is the even odd rule, which is the one I use in my implementation and for the rest of this post. I draw a ray from the given point to outside the bounds of the path. I then count how many times the ray intersects the path. If it is an odd number of times, then the point is inside the path. If even, it&#8217;s outside.</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/07/EvenOddRule1.png" alt="EvenOddRule" border="0" width="500" height="250" /></p>
<p>The star in the above diagram is one closed path. I&#8217;ve added three points A, B, and C to various places in the diagram, and applied the even odd rule to determine if they&#8217;re inside the star or not. The red arrow represents the ray I drew from the point to the outside of the path. (It doesn&#8217;t have to be a horizontal ray, it can go in any direction.) The ray from point A crosses the path exactly once, an odd number of times meaning it falls inside the star. The ray from point C crosses the path twice (even) so it is outside the star. Just by looking at the diagram it&#8217;s easy to see that A is inside and C is outside.</p>
<p>However, when I cast a ray from point B it also intersects with the star an even number of times, meaning it lies outside the path. This isn&#8217;t necessarily intuitive by looking at the diagram, but it is important for allowing holes in a path.</p>
<p>Both the winding rule and the even odd rule are called fill rules, because their main purpose is to determine which parts of a path are filled. Using the even odd rule the star above would be filled like:</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/07/EvenOddRuleFill.png" alt="EvenOddRuleFill" border="0" width="500" height="250" /></p>
<p>The star has a hole in the middle. However, this isn&#8217;t the only way holes can be introduced to a path. Holes can be formed by unconnected subpaths. For example:</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/07/RectangleHoleFill.png" alt="RectangleHoleFill" border="0" width="500" height="250" /></p>
<p>Here both the rectangle and ellipse are part of the same path; they&#8217;re just disjoint subpaths. As with the star, the same even odd rule applies meaning point A is inside the path, but B is not. The rectangle would be filled, except for the area the ellipse defines.</p>
<h2>Nonintersecting Paths</h2>
<p>Now that I&#8217;m done with that detour into fill rules and holes, I want to get back to boolean operations between two paths. I started with how to compute the results of a boolean operation if the two paths intersect, but what if the paths don&#8217;t intersect? There are two non-intersecting states I care about: when one path contains the other, and when the two paths lie outside of each other. I&#8217;ll start with two examples illustrating both of these states:</p>
<table>
<tr>
<td>Contained</td>
<td>
<img src="http://losingfight.com/blog/wp-content/uploads/2011/07/ContainedPaths.png" alt="ContainedPaths" border="0" width="500" height="250" />
</td>
</tr>
<tr>
<td>Disjoint</td>
<td>
<img src="http://losingfight.com/blog/wp-content/uploads/2011/07/DisjointPaths.png" alt="DisjointPaths" border="0" width="500" height="250" />
</td>
</tr>
</table>
<p>For the union operation, I want to eliminate any paths that are contained by another path. However a path is only contained by another if it falls inside the filled region as defined by the even odd rule. If the two paths lie outside of each other, the result of a union is both of them. So union-ing my two examples would result in:</p>
<table>
<tr>
<td>Contained</td>
<td>
<img src="http://losingfight.com/blog/wp-content/uploads/2011/07/UnionContainedPaths.png" alt="UnionContainedPaths" border="0" width="500" height="250" />
</td>
</tr>
<tr>
<td>Disjoint</td>
<td>
<img src="http://losingfight.com/blog/wp-content/uploads/2011/07/UnionDisjointPaths.png" alt="UnionDisjointPaths" border="0" width="500" height="250" />
</td>
</tr>
</table>
<p>Intersect, being the logical and, eliminates any area where both paths aren&#8217;t filled. In the case where one path contains another, the contained path is the one where both paths are filled. If the two paths don&#8217;t overlap in any way, then the result is nil.</p>
<table>
<tr>
<td>Contained</td>
<td>
<img src="http://losingfight.com/blog/wp-content/uploads/2011/07/IntersectContainedPaths.png" alt="IntersectContainedPaths" border="0" width="500" height="250" />
</td>
</tr>
<tr>
<td>Disjoint</td>
<td>
<p style="text-align: center;">(nil)</p>
</td>
</tr>
</table>
<p>Difference starts with one path, which I&#8217;ll call A, and removes all the places that another path, B, fills. In the case of containment which path contains the other matters. If I&#8217;m computing A &#8211; B, and A contains B, then I&#8217;ll add B as a hole subpath to path A. If B contains A, then all of A subtracted away, and I&#8217;m left with nil. If the paths don&#8217;t overlap, and I&#8217;m computing A &#8211; B, then nothing changes and I&#8217;m left with A as the result.</p>
<p>For this example, assume the blue rectangle is A and the red ellipse is B.</p>
<table>
<tr>
<td>Contained (A &#8211; B)</td>
<td>
<img src="http://losingfight.com/blog/wp-content/uploads/2011/07/DifferenceContainedPaths.png" alt="DifferenceContainedPaths" border="0" width="500" height="250" />
</td>
</tr>
<td>Contained (B &#8211; A)</td>
<td>
<p style="text-align: center;">(nil)</p>
</td>
</tr>
<tr>
<td>Disjoint (A &#8211; B)</td>
<td>
<img src="http://losingfight.com/blog/wp-content/uploads/2011/07/DifferenceABDisjointPaths.png" alt="DifferenceABDisjointPaths" border="0" width="500" height="250" />
</td>
</tr>
<tr>
<td>Disjoint (B &#8211; A)</td>
<td>
<img src="http://losingfight.com/blog/wp-content/uploads/2011/07/DifferenceBADisjointPaths.png" alt="DifferenceBADisjointPaths" border="0" width="500" height="250" />
</td>
</tr>
</table>
<h2>Intersecting Holes</h2>
<p>Now that I&#8217;ve discovered holes, it&#8217;s time to see what happens when a path intersects with one. The process is the same as performing the operations on two normal paths, except which section (inside or outside) I chose to go in the result. I&#8217;ll start with a simple example:</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/07/Hole.png" alt="Hole" border="0" width="500" height="250" /></p>
<p>In the above diagram, the blue rectangle and ellipse form one path, with the ellipse being a hole. The red circle forms the second path. As before the inside sections of the intersecting (sub)paths are shown in a dashed style.</p>
<p>For a union I&#8217;d normally choose the outside sections of both paths. However since the blue ellipse is a hole, the red circle should intrude into it. So I would pick the inside of the red circle and the outside of the blue ellipse. More generally, I would always pick the outside section of a path, unless the other path was a hole, then I&#8217;d pick the inside section. The union result would be:</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/07/UnionHole.png" alt="UnionHole" border="0" width="500" height="250" /></p>
<p>Note that since the blue rectangle is nonintersecting, it passes straight through to the result. (See the previous section about nonintersecting paths.)</p>
<p>Intersect would normally choose the inside sections of each path. However, both paths clearly don&#8217;t exist inside of a hole. So when I choose which section to output for a given path, if the other path is a hole I&#8217;ll pick the outside section instead of the usual inside section. Here are the results of the intersect on these two paths:</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/07/IntersectHole.png" alt="IntersectHole" border="0" width="500" height="250" /></p>
<p>In the intersect I remove the blue rectangle entirely, since it is a nonintersecting (sub)path.</p>
<p>In a difference operation the order of the operands matters, so I&#8217;ll take each direction separately. If I subtract the red (path B) from the blue (path A), normally I would chose the outside of A and the inside of B. However, just from eyeballing the paths I can tell that I should take the outside of B. When choosing which section to output for B, I look to see if A is a hole. If it is, I take the outside of B instead the inside, resulting in:</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/07/DifferenceABHole.png" alt="DifferenceABHole" border="0" width="500" height="250" /></p>
<p>To compute B &#8211; A, I would usually pick the outside of B and the inside of A. But since A is a hole, I choose the inside of B, with the following results:</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/07/DifferenceBAHole.png" alt="DifferenceBAHole" border="0" width="500" height="250" /></p>
<p>By now I&#8217;ve noticed a pattern for all the boolean operations. I choose the section of a path I normally would for that operation, unless the intersecting path is a hole. If it is I pick the opposite section than I normally would.</p>
<h2>Exclusive Or Revisited</h2>
<p>Now that I know about holes and how to perform union, intersect and difference on non-intersecting paths I can tackle exclusive or. I&#8217;ll return to the first example:</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/07/RectangleCircleWireframe.png" alt="RectangleCircleWireframe" border="0" width="507" height="413" /></p>
<p>Now I take both the union and the intersect of both these paths, then subtract the intersect from the union for the final result. Below is the intermediate step after the union and intersect have been computed, but before the difference.</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/07/XorStep1.png" alt="XorStep1" border="0" width="507" height="413" /></p>
<p>The union is in blue, and the intersect is in red. This diagram is a good illustration of an edge case. Technically there are two intersections between these two paths where the original rectangle and ellipse meet. However the two paths don&#8217;t fully cross each other at these intersections, they just meet at a point. Because of this, I ignore them. This holds true for any intersection: if the paths don&#8217;t cross each other then I ignore it for the purposes of boolean operations.</p>
<p>Since there are no crossing intersections, taking the difference happens between two paths that don&#8217;t intersect, and I fall back to those rules. The result of the xor:</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/07/XorFinal.png" alt="XorFinal" border="0" width="507" height="413" /></p>
<p>There are two subpaths in the result: the union and the intersect subpaths. The interior subpath from the intersect thus forms a hole. If the result were filled, it would be:</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/07/XorFilled.png" alt="XorFilled" border="0" width="507" height="413" /></p>
<h2>Conclusion</h2>
<p>All these pieces come together to be able to handle boolean operations for complex paths. First I handle all the intersecting subpaths as described, whether they are fill or hole. Then I process all nonintersecting subpaths, ignoring any intersecting subpaths for those computations.</p>
<p>This time I focused strictly on how to perform the boolean operations conceptually, based on the assumption I could find all the intersections. I covered how to think about paths as inside and outside sections, and how to perform boolean operations based on picking the correct section from each path. This is an important foundation for next time, when I&#8217;ll dig into the algorithms that actually implement these boolean operations.</p>
]]></content:encoded>
			<wfw:commentRss>http://losingfight.com/blog/2011/07/07/how-to-implement-boolean-operations-on-bezier-paths-part-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to implement boolean operations on bezier paths, Part 1</title>
		<link>http://losingfight.com/blog/2011/07/06/how-to-implement-boolean-operations-on-bezier-paths-part-1/</link>
		<comments>http://losingfight.com/blog/2011/07/06/how-to-implement-boolean-operations-on-bezier-paths-part-1/#comments</comments>
		<pubDate>Thu, 07 Jul 2011 04:58:10 +0000</pubDate>
		<dc:creator>andy</dc:creator>
				<category><![CDATA[Graphics]]></category>
		<category><![CDATA[Macintosh]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://losingfight.com/blog/?p=438</guid>
		<description><![CDATA[Something any serious vector graphics application has to implement is boolean operations. Boolean operations allow the user to combine bezier paths in interesting and powerful ways to create new shapes. The four common ones are: Operation Example (None) Union (Logical Or) Intersect (Logical And)&#160;&#160;&#160;&#160;&#160; Difference Join (Exclusive Or) Implementing them is somewhat involved, so I&#8217;m [...]]]></description>
			<content:encoded><![CDATA[<p>Something any serious vector graphics application has to implement is boolean operations. Boolean operations allow the user to combine bezier paths in interesting and powerful ways to create new shapes. The four common ones are:</p>
<table>
<tr>
<th>
Operation
</th>
<th>
Example
</th>
</tr>
<tr>
<td>
(None)
</td>
<td>
<img src="http://losingfight.com/blog/wp-content/uploads/2011/07/Original.png" alt="Original" border="0" width="254" height="207" />
</td>
</tr>
<tr>
<td>
Union (Logical Or)
</td>
<td>
<img src="http://losingfight.com/blog/wp-content/uploads/2011/07/Union.png" alt="Union" border="0" width="254" height="207" />
</td>
</tr>
<tr>
<td>
Intersect (Logical And)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</td>
<td>
<img src="http://losingfight.com/blog/wp-content/uploads/2011/07/Intersect.png" alt="Intersect" border="0" width="254" height="207" />
</td>
</tr>
<tr>
<td>
Difference
</td>
<td>
<img src="http://losingfight.com/blog/wp-content/uploads/2011/07/Difference.png" alt="Difference" border="0" width="254" height="207" />
</td>
</tr>
<tr>
<td>
Join (Exclusive Or)
</td>
<td>
<img src="http://losingfight.com/blog/wp-content/uploads/2011/07/Join.png" alt="Join" border="0" width="254" height="207" />
</td>
</tr>
</table>
<p>Implementing them is somewhat involved, so I&#8217;m breaking the explanation up into two articles. This post will focus on finding intersections between individual bezier curves, and the next will show how to implement the boolean operations based on that. The algorithm presented will be able to handle arbitrary closed bezier paths, including those with holes and self intersections.</p>
<p>If you&#8217;re impatient, you can skip straight to the <a href="https://bitbucket.org/andyfinnell/vectorboolean">commented source code</a>. As usual, I&#8217;ve released it under the MIT license. I encourage you to play with the sample application to see what it can do.</p>
<h2>Clipping until it converges</h2>
<p>This post I&#8217;m focusing on finding intersections between individual bezier curves using an algorithm called bezier clipping. It&#8217;s described in the paper <a href="http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf">&#8220;Curve intersection using Bezier clipping&#8221; by TW Sederberg and T Nishita</a>. If you&#8217;re following along in the source code, it&#8217;s implemented in the FBBezierCurve class.</p>
<p>The first thing to realize is that finding intersections between curves isn&#8217;t exact. I won&#8217;t be able to plug the inputs into a formula and get back all the points where the curves intersect. Instead, I&#8217;ll iteratively whittle down the curves to ranges that could possibly intersect until I get down to a point or eliminate the curve entirely.</p>
<p>So the pseudocode for the main loop would be:</p>
<p><code></p>
<pre>
FBBezierCurve *us = ...; // passed in
FBBezierCurve *them = ...; // passed in
FBRange usRange = FBRangeMake(0, 1);
FBRange themRange = FBRangeMake(0, 1);
while ( !FBRangeHasConverged(usRange) &#038;&#038; !FBRangeHasConverged(themRange) ) {
	BOOL intersects = NO;
	us = [us bezierClipWithBezierCurve:them range:&amp;usRange intersects:&amp;intersects];
	if ( !intersects )
		return; // no intersections
	them = [them bezierClipWithBezierCurve:us range:&amp;themRange intersects:&amp;intersects];
	if ( !intersects )
		return; // no intersections
}
</pre>
<p></code></p>
<p>Here a FBBezierCurve is one cubic bezier curve, as defined by two end points and two control points. FBRange is a parameter range defined by a minimum and maximum. A parameter value falls between [0..1] and is used for the parametric form of a bezier curve. In my case it keeps track of the range of the curve that could possibly intersect with the other curve.</p>
<p>The method bezierClipWithBezierCurve: refines the range passed in by determining the range where self could intersect with the curve passed in. It can also determine if there is no range where the two curves intersect. Don&#8217;t worry about how this is done right now, I&#8217;ll explain it later.</p>
<p>Each time through the loop I clip each curve a bit more, refining the range where the two curves might possibly intersect. The refined range is fed into the next iteration of the loop, which refines it a bit more. This continues until the minimum and maximum values of the range are close enough to be satisfactory (in my implementation, six decimal places). It&#8217;s also possible I discover, in clipping one curve against the other, that they don&#8217;t intersect at all. In that case, I can stop there.</p>
<p>The pseudocode above handles the common case where there is one (or no) intersection between the two curves. However cubic bezier curves can intersect up to nine times, so I need a way to detect when there are multiple intersections, and a way to find them. Detecting the possibility is easy; each time through the loop I compute how much I&#8217;ve reduced the intersection ranges by. If it&#8217;s less than 20%, then it&#8217;s likely there are multiple intersections, which would prevent the range from converging quickly.</p>
<p>Once I detect that I might have multiple intersections, I look at which range (and thus curve) is bigger. I split the correspond curve in half. I then recurse: for each of the halves I find the intersections between it and the other full curve. I take the combined results and return.</p>
<p>If you want to see the main loop in all it&#8217;s excruciating detail, check out the commented intersectionsWithBezierCurve:usRange:themRange:originalUs:originalThem: method. There are some implementation details I didn&#8217;t cover here, but are explained in the comments.</p>
<h2>Fat Lines</h2>
<p>In the previous section I glossed over how I can refine the range of a curve that could possibly intersect with the other curve. I&#8217;ll tackle how to do that now.</p>
<p>What I really need is a way to more simply represent the area a given bezier curve could possibly inhabit. Once I have that I can determine which parts of the other bezier lie inside of that area (and thus possibly intersect), and which don&#8217;t.</p>
<p>To this end, Sederberg and Nishita introduce the concept of a fat line. A fat line is a line through the end points of the bezier curve, but fat enough it encloses the entire curve.</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/07/FatLine1.png" alt="FatLine" border="0" width="500" height="250" /></p>
<p>Above you can see the bezier curve in blue and the fat line in the pink color, crossing through the curve&#8217;s end points. In code, the fat line is represented by a line (the dashed line above), plus two signed distances describing how far to extend the fat line above and below the dashed line. (Signed distance just means the value is negative if it falls below the line, positive if above.) The two distances form the bounds of the fat line, and are called the minimum and maximum bounds.</p>
<p>Computing an approximation to the minimum and maximum bounds is straightforward if I take advantage of the <a href="http://en.wikipedia.org/wiki/Bézier_curve">convex hull property</a>. The convex hull is the polygon formed by connecting the end and control points with line segments. The convex hull property states that the polygon will completely enclose the bezier curve, as you can see below. The curve is in blue and the convex hull in red.</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/07/ConvexHull.png" alt="ConvexHull" border="0" width="500" height="250" /></p>
<p>So to compute the minimum and maximum bounds, I just compute the signed distances of the end and control points from the dashed line and chose the minimum and maximum distances.</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/07/ConvexHullFatLine.png" alt="ConvexHullFatLine" border="0" width="500" height="300" /></p>
<p>As you can see, using the convex hull to compute the minimum and maximum bounds doesn&#8217;t produce optimal results (i.e. the fat line fits loosely around the curve, not tightly). However the approximate bounds are cheap to compute and are good enough for my purposes.</p>
<p>Based on the fat line, it&#8217;s easy to see if any given point could possibly intersect with the bezier curve. Simply compute the signed distance from the line to the point. If that signed distance lies inside the fat line bounds, then it could intersect. If not, then it definitely doesn&#8217;t intersect.</p>
<h2>Bezier clipping</h2>
<p>I&#8217;ve simplified the clipping curve to a fat line and bounds, and can use it to see if a point could lie inside the clipping curve. Next I need to clip the subject bezier curve with the fat line.</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/07/FatLineClip.png" alt="FatLineClip" border="0" width="500" height="250" /></p>
<p>The above diagram shows a range on the subject bezier that falls inside of the fat line, and thus could intersect with the other bezier. The piece inside the fat line is the bezier curve I want to end up with.</p>
<p>I start by calculating the signed distances of the end and control points of the subject bezier to the fat line. Next I construct a bezier curve from these distances, like so:</p>
<p><code></p>
<pre>
NSPoint endPoint1 = NSMakePoint(0, distance(fatline, subjectCurve.endPoint1));
NSPoint controlPoint1 = NSMakePoint(1.0/3.0, distance(fatline, subjectCurve.controlPoint1));
NSPoint controlPoint2 = NSMakePoint(2.0/3.0, distance(fatline, subjectCurve.controlPoint2));
NSPoint endPoint2 = NSMakePoint(1, distance(fatline, subjectCurve.endPoint2));
</pre>
<p></code></p>
<p>I spread the distance bezier points out evenly between 0.0 and 1.0 on the X axis, and use the distances from the fat line as Y values. By uniformly spreading the X values out, they will correspond to parameter values for the parametric form of the subject bezier.</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/07/DistanceBezier.png" alt="DistanceBezier" border="0" width="500" height="250" /></p>
<p>Since the Y axis is the distance from the fat line, I can just throw the fat line bounds on the graph.</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/07/DistanceBezierSource.png" alt="DistanceBezierSource" border="0" width="500" height="250" /></p>
<p>If I can calculate the X values of where the distance bezier crosses the minimum and maximum bounds, then I&#8217;ll have the range of the subject bezier that falls inside the fat line. To do that, I&#8217;ll once again rely on the convex hull property.</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/07/DistanceBezierWithFatLineConvexHull.png" alt="DistanceBezierWithFatLineConvexHull" border="0" width="500" height="250" /></p>
<p>In the above diagram, the convex hull is the dashed red line. Computing the intersection of two lines is easy, so I find the intersections of the convex hull with the horizontal minimum and maximum lines. The lowest and highest X values define the parameter range on the subject bezier curve that fall into the fat line bounds, and thus could intersect the other curve.</p>
<p>There are two special cases here, both occurring when the distance bezier doesn&#8217;t intersect with the minimum or maximum fat line bounds. If the distance bezier falls completely inside the fat line bounds, then I can&#8217;t whittle the subject bezier down any, and I&#8217;m forced to return the entire subject bezier untouched. If the distance bezier lies completely outside the fat line bounds, I know the two curves don&#8217;t intersect, and return that.</p>
<p>If I did successfully refine the possible intersecting range, I need to cut down the subject curve to match. Fortunately, <a href="http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/spline/Bezier/bezier-sub.html">de Casteljau&#8217;s algorithm</a> makes it easy to split bezier curves at a specific parameter value. See the BezierWithPoints() helper function for the implementation of that algorithm.</p>
<p>That completes how to clip one bezier curve against another. To summarize: compute a fat line and bounds from the clipping bezier, compute a distance bezier from the other curve, and see where the distance bezier&#8217;s convex hull intersects the fat line bounds. Using the intersections&#8217; x values as the parameter range where the curves could intersect, cut the subject bezier down to match the range.</p>
<h2>Points of interest</h2>
<p>Although the above description presents the complete algorithm for finding intersections between two bezier curves, I wanted to point out a couple of other things. These are implementations details that I either found interesting and/or difficult.</p>
<ol>
<li>
<p>After the main intersection loop (in intersectionsWithBezierCurve:usRange:themRange:originalUs:originalThem:) there&#8217;s a bit of code that checks to see if both curves have converged to a point. The loop bails as soon as one curve converges since the math for clipping falls apart as soon as one curve becomes a point. However for implementing the boolean operations, I need good parameter values for both curves. Since I know the 2D intersection point from the curve that converged, and I can guess a reasonable parameter value for the curve that didn&#8217;t, I can use Newton&#8217;s method to refine the parameter value of the curve that didn&#8217;t converge. Fortunately, that&#8217;s something I&#8217;ve done before when <a href="http://losingfight.com/blog/2011/05/30/how-to-implement-a-vector-brush/">fitting curves to points</a>.</p>
</li>
<li>
<p>
In the method that clips one bezier curve against the other (bezierClipWithBezierCurve:original:rangeOfOriginal:intersects:) you&#8217;ll notice that I don&#8217;t compute and clip against one fat line, but two. The second fat line is perpendicular to the regular one:</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/07/PerpendicularFatLine.png" alt="PerpendicularFatLine" border="0" width="500" height="250" /></p>
<p>Most of the time the regular fat line will clip out more of the curve than the perpendicular one. However, clipping against the perpendicular fat line does help the possible intersection range converge more quickly.</p>
</li>
<li>
<p>I mention the convex hull a couple of times, but gloss over how to build it. It is made up of just the end and control points, but the order is important, and sometimes points need to be removed if they&#8217;re collinear. There are several algorithms to build the convex hull, but <a href="http://en.wikipedia.org/wiki/Graham_scan">Graham Scan</a> is supposedly the best for 2D curves. It took me a few tries to get it right. Not all of the reference implementations/descriptions that I found covered the edges cases, such as what to do when I encountered collinear points. The best I found ended up being <a href="http://softsurfer.com/Archive/algorithm_0109/algorithm_0109.htm">this one</a>.</p>
<p>Check out the convexHull method for my implementation.</p>
</li>
</ol>
<h2>Conclusion</h2>
<p>Although I&#8217;m finding bezier curve intersections for the purpose of performing boolean operations, it can be used for other applications as well. Heck if I know what those are though. So next time I&#8217;ll dive into implementing union, intersect, difference, and join.</p>
<p>Be sure to enjoy the <a href="https://bitbucket.org/andyfinnell/vectorboolean">complimentary source code</a> in the mean time.</p>
]]></content:encoded>
			<wfw:commentRss>http://losingfight.com/blog/2011/07/06/how-to-implement-boolean-operations-on-bezier-paths-part-1/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>How to implement a vector brush</title>
		<link>http://losingfight.com/blog/2011/05/30/how-to-implement-a-vector-brush/</link>
		<comments>http://losingfight.com/blog/2011/05/30/how-to-implement-a-vector-brush/#comments</comments>
		<pubDate>Tue, 31 May 2011 06:14:15 +0000</pubDate>
		<dc:creator>andy</dc:creator>
				<category><![CDATA[Graphics]]></category>
		<category><![CDATA[Macintosh]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://losingfight.com/blog/?p=420</guid>
		<description><![CDATA[Since I&#8217;ve previously written about how to implement a basic bitmap brush I thought it would be fun to figure out how to build a vector brush, like what you would find in Adobe Illustrator or Fireworks. A vector brush works the same as a bitmap brush from the viewpoint of the user, except that [...]]]></description>
			<content:encoded><![CDATA[<p>Since I&#8217;ve previously written about how to <a href="/blog/2007/08/18/how-to-implement-a-basic-bitmap-brush/">implement a basic bitmap brush</a> I thought it would be fun to figure out how to build a vector brush, like what you would find in Adobe Illustrator or Fireworks. A vector brush works the same as a bitmap brush from the viewpoint of the user, except that the resulting brushing stroke is scalable and otherwise editable after it is made. That&#8217;s because the resulting brush stroke ends up being a bezier path. In this post, I&#8217;ll show how it&#8217;s done.</p>
<p>If you&#8217;re impatient, you can always <a href="https://bitbucket.org/andyfinnell/vectorbrush">skip to the source code</a>. It is licensed under the MIT license.</p>
<h2>Naive Implementation</h2>
<p>The direct way to implement the vector brush would be to simply record the mouse movements into a NSBezierPath. On a mouse down, create an NSBezierPath, do a move to the first point, then on subsequent mouse drags add line to&#8217;s to the NSBezierPath. Since I already have an NSBezierPath now, I can just draw it to represent the brush stroke. If you run the sample application with all the options under the Options menu (Show Points, Simplify Path, and Fit Curve) turned off, it&#8217;ll do exactly that. A brush stroke will look something like:</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/05/naive-vector-brush.png" alt="Naive vector brush" border="0" width="350" height="100" /></p>
<p>That actually doesn&#8217;t look bad. Does that mean I&#8217;m done? To answer myself, I&#8217;ll turn on the Show Points option under the Options menu:</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/05/naive-vector-brush-show-points.png" alt="Naive vector brush show points" border="0" width="350" height="100" /></p>
<p>Show Points draws an orange, hollow square around each of the points that make up the path. As you can see, there are a ton of them, about 160 in this case. Having that many points means editing the path afterwards is going to be rather difficult. Also, I can see that most of the points are redundant; they aren&#8217;t adding any new information to the path.</p>
<h2>Brush strokes, simplified</h2>
<p>At this point the best way to improve the my brush is to remove all the redundant points from our NSBezierPath. Since all the extra points don&#8217;t get in my way until mouse up happens, I&#8217;ll simply do some post processing on the NSBezierPath on mouse up. I&#8217;ll use the Ramer-Douglas-Peucker algorithm to identify and remove the redundant points. To demonstrate the effects of this algorithm, I&#8217;ll turn on the Simplify Path option, and draw another brush stroke:</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/05/simplify-path-vector-brush.png" alt="Simplify path vector brush" border="0" width="310" height="100" /></p>
<p>You can see a big difference here in the number of points required to make up the path. The sample application outputs (using NSLog) how many points the path had before and after simplifying the path. In this case, the points went down from 170 to 15.</p>
<h3>The Idea</h3>
<p>The idea behind the Ramer-Douglas-Peucker algorithm is pretty simple. It takes a path and a threshold as parameters. I&#8217;ll show an example to demonstrate it. Let&#8217;s start with the following path:</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/05/simplify-path-example-1.png" alt="Simplify path example 1" border="0" width="300" height="150" /></p>
<p>I&#8217;ve numbered the points for easy reference. To start with I imagine a line between the end points, 1 and 5. I then measure the distance between each of the interior points (2, 3, 5) and the line made by points 1 and 5.</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/05/simplify-path-example-2.png" alt="Simplify path example 2" border="0" width="300" height="150" /></p>
<p>I take the greatest distance (the one between point 3 and my line) and compare it to the threshold passed in. If the distance exceeds the threshold, I have to subdivide the path and recurse. I split the path at the greatest distance (point 3 in this case), which gives me two paths: [1, 2, 3] and [3, 4, 5].</p>
<p>I repeat the process on [1, 2, 3] as my path:</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/05/simplify-path-example-3.png" alt="Simplify path example 3" border="0" width="300" height="150" /></p>
<p>Here my end points are 1 and 3, and my only interior point is 2. Like before I take the distance between point 2 and the line formed by 1 and 3, and compare it to the threshold passed in. In this case, the distance is less than threshold. Thus, I can say the interior points are all redundant and the path [1, 2, 3] can be represented by the endpoints 1 and 3.</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/05/simplify-path-example-4.png" alt="Simplify path example 4" border="0" width="300" height="150" /></p>
<p>Going back to the second recursion mentioned, I repeat the same process on [3, 4, 5]. In this case the distance between point 4 and the line between points 3 and 5 is less than the threshold. Because of that, I can represent the path [3, 4, 5] with just the end points 3 and 5. Thus, the final result is:</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/05/simplify-path-example-5.png" alt="Simplify path example 5" border="0" width="300" height="150" /></p>
<h3>The Code</h3>
<p>As you might expect the code for this algorithm is rather simple. It&#8217;s just one method (not counting the utility methods to access NSBezierPath data), which I&#8217;ve added as a category to NSBezierPath.</p>
<p>It takes a threshold as a parameter and returns the simplified path. It needs at least three points on the path before the algorithm will work.</p>
<p><code></p>
<pre>
- (NSBezierPath *) fb_simplify:(CGFloat)threshold
{
    if ( [self elementCount] &lt;= 2 )
        return self;
</pre>
<p></code></p>
<p>Next it calculates the distance between the interior points and the line formed by the two end points. It remembers the largest distance and where in the path that point is.</p>
<p><code></p>
<pre>
    CGFloat maximumDistance = 0.0;
    NSUInteger maximumIndex = 0;

    // Find the point the furtherest away
    for (NSUInteger i = 1; i &lt; ([self elementCount] - 1); i++) {
        CGFloat distance = FBDistancePointToLine([self fb_pointAtIndex:i], [self fb_pointAtIndex:0], [self fb_pointAtIndex:[self elementCount] - 1]);
        if ( distance &gt; maximumDistance ) {
            maximumDistance = distance;
            maximumIndex = i;
        }
    }
</pre>
<p></code></p>
<p>FBDistancePointToLine() is a function I wrote that calculates the distance between a point and a line. fb_pointAtIndex is just a helper method that returns the point on the path at that index.</p>
<p>Now that it has the greatest distance, it checks to see if that distance is significant. If it is, then it recurses on itself, passing in the two halves split by the greatest distance. When the recursive calls return it joins the two results back into one, and returns those.</p>
<p><code></p>
<pre>
    if ( maximumDistance &gt;= threshold ) {
        // The distance is too great to simplify, so recurse
        NSBezierPath *results1 = [[self fb_subpathWithRange:NSMakeRange(0, maximumIndex + 1)] fb_simplify:threshold];
        NSBezierPath *results2 = [[self fb_subpathWithRange:NSMakeRange(maximumIndex, [self elementCount] - maximumIndex)] fb_simplify:threshold];

        [results1 fb_appendPath:[results2 fb_subpathWithRange:NSMakeRange(1, [results2 elementCount] - 1)]];
        return results1;
    }
</pre>
<p></code></p>
<p>fb_subpathWithRange: is another utility method. It makes a copy of part of the path specified, and returns it. fb_appendPath appends one path to another, except it also will remove spurious move to&#8217;s and replace them with line to&#8217;s.</p>
<p>Finally, if the greatest distance isn&#8217;t significant, then all the interior points are redundant. In this case, just create a new path with the two end points.</p>
<p><code></p>
<pre>
    NSBezierPath *path = [NSBezierPath bezierPath];
    [path fb_copyAttributesFrom:self];
    [path moveToPoint:[self fb_pointAtIndex:0]];
    [path lineToPoint:[self fb_pointAtIndex:[self elementCount] - 1]];
    return path;
}
</pre>
<p></code></p>
<p>The only new utility method this time is fb_copyAttributesFrom:, which copies over attributes like caps, joins, and miters to the target path.</p>
<h2>Curvy is better</h2>
<p>So now I have a much simplified path representing my brush stroke. But my path is comprised of lines only, which are quite limited in representing anything other than a line. I&#8217;d like to have a way to represent curves. That way editing the path afterward would be even more powerful, plus I could reduce the number of total points on my path even more. Enter bezier curves.</p>
<p>Defining bezier curves is beyond the scope of this article. As far as this post is concerned they are a parametric curve defined by four points: two end points and two control points.</p>
<p>To further improve my brush stroke, I&#8217;m going to take my simplified path of lines, and fit a series of bezier curves to it. The algorithm for doing this is documented in Graphics Gems 1 in the article titled &#8220;An Algorithm for Automatically Fitting Digitized Curves&#8221; by Philip J. Schneider. Unfortunately, Graphics Gems is out of print. A Kindle version is available on Amazon, but it is 1) US$80 and 2) a poor quality scan. I would suggest buying the book used if you want a copy.</p>
<p>You can see the results of curve fitting by turning on the Fit Curve options in the Options menu and drawing a stroke. Here&#8217;s an example:</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/05/fit-curve-vector-brush.png" alt="Fit curve vector brush" border="0" width="330" height="110" /></p>
<p>The black boxes are bezier curve control points. In this case using both path simplification and curve fitting reduced the number points from 197 to 7. Even better, bezier curves give the user more flexibility and power when it comes to editing the path.</p>
<h3>Curve fitting overview</h3>
<p>The curve fitting technique is somewhat involved and makes use of several different algorithms. I&#8217;ll only cover the methods unique to the algorithm and skip over a lot of details. That said,  <a href="https://bitbucket.org/andyfinnell/vectorbrush">the sample code</a> is complete and commented, so it can be used to fill in the details.</p>
<p>To start with, I&#8217;ll assume the function Q(t) represents a bezier curve that fits the points on my path. The parameter, t, ranges from 0 to 1, and Q(t) outputs x,y coordinates on my bezier curve. The first thing to do is calculate estimated values of t that match up to the points on my path. That is, Q(t[index]) should equal the point on my path at index. </p>
<p>After generating inputs for Q(t), the next step is to try to fit one bezier curve to the all the points on the path given the inputs. (I&#8217;ll describe the exact process later.) I&#8217;ll then compute how far the resulting bezier curve falls from the points on my path. If the curve is close enough, then I&#8217;m done.</p>
<p>If the bezier curve isn&#8217;t close enough to fit, I&#8217;ll see if it&#8217;s close enough that it makes sense to refine the inputs (t). If it is, I&#8217;ll repeatedly refine the input parameters (t) using <a href="http://en.wikipedia.org/wiki/Newton%27s_method">Newton&#8217;s Method</a>, until the resulting bezier curve fits sufficiently or I try more than four times.</p>
<p>If refining the input parameters doesn&#8217;t lead to a fit, it&#8217;s time to give up on one bezier curve, divide the path, and recurse. I&#8217;ll split the path into two at the point the bezier curve is furtherest from (i.e. where the greatest error is at). I&#8217;ll then recurse on the two halves, and then combine the two resulting curves into one bezier path for the final result.</p>
<p>The method fb_fitCubicToRange: in the NSBezierPath (FitCurve) category contains the code for the process described above if you want more detail.</p>
<h3>Fitting a bezier curve to points</h3>
<p>Remember that a bezier curve is defined by four points, like below.</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/05/bezier-curve-points.png" alt="Bezier curve points" border="0" width="300" height="150" /></p>
<p>Here points 1 and 4 are the end points and 2 and 3 are the control points. The orange lines just visually connect the control point with its corresponding end point. The blue curve is the bezier itself.</p>
<p>If we&#8217;re given a path of points to fit a curve to:</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/05/path-points1.png" alt="Path points" border="0" width="300" height="150" /></p>
<p>it&#8217;s easy to select the end points of the bezier curve; they&#8217;re simply the end points of the path (1 and 6 here). The direction of the control points relative to their end points is also simple to determine: simply compute the vector between the path end points and their nearest neighbor. In this case the direction of the left control point is the vector between points 1 and 2 in the path. The right control point direction is the vector between points 5 and 6. The only unknown in constructing our bezier curve is the distance between the control points and their respective end point.</p>
<p>Stated another way:</p>
<p><code></p>
<pre>
leftEndPoint = first point in path
rightEndPoint = last point in path
leftControlPoint = leftAlpha * leftTangent + leftEndPoint
rightControlPoint = rightAlpha * rightTangent + rightEndPoint
</pre>
<p></code></p>
<p>Where leftAlpha is the distance between the leftEndPoint and leftControlPoint, and rightAlpha is the distance between the rightEndPoint and the rightControlPoint. leftTangent and rightTangent are the unit vectors between the end points of the path and their closest neighbors.</p>
<p>By controlling the distance of the control points from their end points, I can affect the curve of the bezier. I want to chose distances (leftAlpha and rightAlpha) such that it best fits the points in the path. Formally stated, I want to minimize the squared errors as represented by:</p>
<p><code></p>
<pre>
S = SUM( (point[i] - Q(t[i])) ^ 2 )
</pre>
<p></code></p>
<p>Where point[i] is the point on the path at index i, t[i] is one of the estimated parameters I generated earlier, and Q is bezier curve. Remember that point[i] should be equal to Q(t[i]), assuming the bezier curve fits perfectly my points. Here I&#8217;m calculating how far each point on the bezier curve is off, squaring that, then adding it all up (squared errors). This is the error I calculate when I&#8217;m trying to determine if a bezier curve is close enough that I&#8217;m done. Right now though, I want to minimize S when calculating leftAlpha and rightAlpha.</p>
<p>Using the <a href="http://mathworld.wolfram.com/LeastSquaresFitting.html">least squares approach</a> I can write the equations I want to solve as:</p>
<p><code></p>
<pre>
d(S) / d(leftAlpha) = 0
d(S) / d(rightAlpha) = 0
</pre>
<p></code></p>
<p>Here d() is derivative, usually written as the Greek letter delta. S is the squared errors defined above.</p>
<p>At this point I do need to introduce the definition of a bezier curve:</p>
<p><code></p>
<pre>
Q(t) = SUM(V[i] * Bernstein[i](t))
</pre>
<p></code></p>
<p>Where i ranges between [0..3], and V is one of the points on the bezier curve. V[0] is the leftEndPoint, V[1] the leftControlPoint, V[2] the rightControlPoint, and V[3] the rightEndPoint. Berstein[i] is a polynomial that is highly regarded as boring for this discussion. (Look at the code if you really want to know.)</p>
<p>Now that I have Q defined, I can substitute it in the equation S, and then S into the two equations I want to solve. After a lot of mathematical voodoo and gymnastics (see the paper for all of that), I arrive at:</p>
<p><code></p>
<pre>
leftAlpha = det(X * C2) / det(C1 * C2)
rightAlpha = det(C1 * X) / det(C1 * C2)
</pre>
<p></code></p>
<p>Here det() is determinant, * is the dot product, and X, C1, and C2 are all 2&#215;1 matrices defined below.</p>
<p><code></p>
<pre>
C1 = [SUM(A1[i] * A1[i]), SUM(A1[i] * A2[i])]
C2 = [SUM(A1[i] * A2[i]), SUM(A2[i] * A2[i])]
X = [SUM(partOfX * A1[i]), SUM(partOfX * A2[i])]
</pre>
<p></code></p>
<p>Where </p>
<p><code></p>
<pre>
partOfX = (points[i] - (leftEndPoint * Bernstein0(t[i]) + leftEndPoint * Bernstein1(t[i]) + rightEndPoint * Bernstein2(t[i]) + rightEndPoint * Bernstein3(t[i])))
</pre>
<p></code></p>
<p>And</p>
<p><code></p>
<pre>
A1[i] = leftTangent * Bernstein1(t[i])
A2[i] = rightTangent * Bernstein2(t[i])
</pre>
<p></code></p>
<p>If you&#8217;re interested in how this all plays out in code, check out the method fb_fitBezierInRange: in the NSBezierPath (FitCurve) category.</p>
<h3>Calculating parameters (i.e. t)</h3>
<p>The parameters (t) are useful for correlating the points on my path with the bezier curve I&#8217;m trying to fit. I know that t has to range from 0 to 1, and Q(t) is supposed to correspond to the points on my path. Q(0) should be the first point on my path, and Q(1) should be the last. </p>
<p>The initial estimate of t uses the <a href="http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/INT-APP/PARA-chord-length.html">chord length method</a>. Ideally, t  would be the length of curve from the left end point to the point corresponding to t, divided by the total length of the curve. However, the chord length method makes the assumption that a straight line is a reasonable estimate of a curve. So to estimate t, I measure the length of the line segments from the left end point to the point corresponding to t, then divide that by the length of all the line segments.</p>
<p>You can inspect the implementation of this in the fb_estimateParametersUsingChordLengthMethodInRange: method.</p>
<p>If my initial estimate proves to be poor, I can further refine it using <a href="http://en.wikipedia.org/wiki/Newton%27s_method">Newton&#8217;s Method</a>. Newton&#8217;s Method says I can refine each t value by:</p>
<p><code></p>
<pre>
t = t - f(t) / f'(t)
</pre>
<p></code></p>
<p>In my case</p>
<p><code></p>
<pre>
f(t) = (Q(t) - point) * Q'(t) = 0
</pre>
<p></code></p>
<p>Here (Q(t) &#8211; point) is the vector from a point on the bezier curve to the corresponding point on my path. Q&#8217;(t) is the first derivative, which is tangent to the bezier curve, Q, at t. (Q(t) &#8211; point) is orthogonal to Q&#8217;(t), which means the dot product of the two is zero.</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2011/05/newtons-method-parameters.png" alt="Newtons method parameters" border="0" width="300" height="150" /></p>
<p>Based on that, f&#8217;(t) is</p>
<p><code></p>
<pre>
f'(t) = (Q(t) - point) * Q''(t) + Q'(t) * Q'(t)
</pre>
<p></code></p>
<p>The NewtonsMethod() function in NSBezierPath+FitCurve.m implements this.</p>
<h3>Conclusion</h3>
<p>Although I skipped over a lot of detail when it came to curve fitting, hopefully this post has been helpful in understanding how it works, in addition to explaining the vector brush. For the details that I skipped over, <a href="https://bitbucket.org/andyfinnell/vectorbrush">the code</a> should fill in the blanks. The vector brush is a fun tool to play with and the curve fitting algorithm has other applications too.</p>
]]></content:encoded>
			<wfw:commentRss>http://losingfight.com/blog/2011/05/30/how-to-implement-a-vector-brush/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>The Story of Hearts Attack</title>
		<link>http://losingfight.com/blog/2010/03/30/the-story-of-hearts-attack/</link>
		<comments>http://losingfight.com/blog/2010/03/30/the-story-of-hearts-attack/#comments</comments>
		<pubDate>Tue, 30 Mar 2010 22:30:31 +0000</pubDate>
		<dc:creator>andy</dc:creator>
				<category><![CDATA[Career]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Order N]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://losingfight.com/blog/?p=379</guid>
		<description><![CDATA[I&#8217;ve already posted the press release for Hearts Attack, but I thought I&#8217;d share a little about how Hearts Attack came about. Way back in 2008 the original iPhone SDK came out, and I, like a lot of people, was excited about developing apps for the iPhone. My company is primarily a software development services [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve already posted the <a href="/blog/2010/03/30/hearts-attack-1-0-announced-fun-card-game-for-the-iphone/">press release for Hearts Attack</a>, but I thought I&#8217;d share a little about how <a href="http://www.orderndev.com/hearts-attack.html">Hearts Attack</a> came about.</p>
<p>Way back in 2008 the original iPhone SDK came out, and I, like a lot of people, was excited about developing apps for the iPhone. My company is primarily a <a href="http://www.orderndev.com">software development services company</a> so I was mainly interested in learning the SDK so we could pick up iPhone contracts in addition to Mac ones. It also happens to be the case that my favorite card game is hearts, so I decided a good way to learn the iPhone SDK was to write my own hearts game. </p>
<p>After a couple of weeks I had the basic functionality implemented, and noticed I was playing it a lot. I realized then that I could probably make this into a product. Furthermore, releasing an iPhone app through the App Store seemed like a good way for us as a company to begin making the transition from a services based company to a product based one.</p>
<p>If I was going to release Hearts Attack as a published app, I knew the UI and presentation had to be greatly improved. I went through a lot of mockups for the main playing view, including one where everyone&#8217;s cards &mdash; all 52 of them &mdash; were always visible somewhere on the table (a truly horrible idea). Unfortunately I don&#8217;t seem to have most of the mockups around anymore, but I found a couple which you can see below. (See the <a href="http://www.orderndev.com/hearts-attack.html">product page</a> for the end result.)</p>
<table>
<tr>
<td><a href="/blog/wp-content/uploads/2010/03/HorizontalLayout.jpg"><img src="/blog/wp-content/uploads/2010/03/HorizontalLayout.jpg" alt="HorizontalLayout.jpg" border="0" width="240" height="160" /></a></td>
<td><a href="/blog/wp-content/uploads/2010/03/VerticalLayout.jpg"><img src="/blog/wp-content/uploads/2010/03/VerticalLayout.jpg" alt="VerticalLayout.jpg" border="0" width="160" height="240" /></a></td>
</tr>
<tr>
<td><a href="/blog/wp-content/uploads/2010/03/VerticalLayout3.jpg"><img src="/blog/wp-content/uploads/2010/03/VerticalLayout3.jpg" alt="VerticalLayout3.jpg" border="0" width="160" height="240" /></a></td>
<td><a href="/blog/wp-content/uploads/2010/03/HorizontalLayout3.jpg"><img src="/blog/wp-content/uploads/2010/03/HorizontalLayout3.jpg" alt="HorizontalLayout3.jpg" border="0" width="240" height="160" /></a></td>
</tr>
</table>
<p>The biggest challenge I had was fitting everything on the screen and it still being legible and usable. By trial and error I figured out how small I could make the cards and still make them tappable, as well as their optimal position to make them accessible with one hand.</p>
<p>I began thinking about what would make Hearts Attack unique or different from its competitors. Back then there were literally just two iPhone hearts games in the App Store, and I felt pretty confident that what I had was already better than them, but I wanted to be sure. I decided on: oddball talking computer opponents, a tutorial that gave not only card suggestions but the rationale behind the choice (a pet peeve of mine), and multiple undo support for mis-taps and tactical errors.</p>
<p>The last step was to get professionals to do the sound and graphics. I ended up hiring a sound designer, a graphics designer, and a character illustrator. The <a href="/blog/2008/12/13/experiences-with-a-sound-designer/">sound design went smoothly</a>, but getting the graphics done was a lot more involved than I anticipated, which is another story for another day. Jordan of <a href="http://onetoad.com">OneToad Design</a> created the app icon, playing backgrounds, and the special card backgrounds for the queen of spades and jack of diamonds. Lara Kehler did the character illustrations, which turned out great.</p>
<p>Unfortunately, Hearts Attack went on hiatus in early 2009. I was working full time on an iPhone contract, and simply didn&#8217;t have a lot of time to put into Hearts. Secondly, I had lost all desire in finishing it. It was becoming increasingly apparent that iPhone users didn&#8217;t want to pay more than $0.99 for anything, despite <a href="/blog/2008/11/15/how-to-price-your-iphone-app-out-of-existence/">all the whining I did about it</a>. I convinced myself it wasn&#8217;t worth releasing Hearts because it would never make back the money it cost us to make. Hearts stayed dormant for an entire year.</p>
<p>A couple of months ago, I decided to pick Hearts Attack back up again. I had the time and, as someone pointed out to me, it would never make money if I didn&#8217;t release it. I was tempted to update the app to the latest SDK (I started Hearts back before you could even use nibs on the iPhone) and add some features. I decided against this, because I really just wanted to ship it. I did have to update it to the 2.2.1 SDK because the current Xcode tools no longer ship with the 2.0 SDK.</p>
<p>Instead I focused on fixing the bugs and adding polish. Fortunately for me my wife happens to be a professional software tester with iPhone experience, so I got lots of good bugs to fix. I also prepared a press release, created a website, and otherwise got ready for the release. After I felt the app was stable enough, I submitted it to Apple on Friday. It was approved on Monday.</p>
<p>At this point, I&#8217;m still not convinced I&#8217;ll ever make back the money we spent on sound and graphic designers. A hearts card game simply is never going to be a big seller, and price point isn&#8217;t high enough to make up for that. Right now, I&#8217;m tending to think pessimistically about sales, but I&#8217;m going to do what I can to drum up sales and see how things go. </p>
<p>It&#8217;s a &#8220;wait and see&#8221; situation as to if we develop any more iPhone applications to sell ourselves. Of course, regardless of how well Hearts Attack does, we&#8217;d be <a href="http://www.orderndev.com/hire.html">happy to develop your iPhone app</a> for you.</p>
]]></content:encoded>
			<wfw:commentRss>http://losingfight.com/blog/2010/03/30/the-story-of-hearts-attack/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Distributed Version Control and Other Religions</title>
		<link>http://losingfight.com/blog/2010/03/22/distributed-version-control-and-other-religions/</link>
		<comments>http://losingfight.com/blog/2010/03/22/distributed-version-control-and-other-religions/#comments</comments>
		<pubDate>Mon, 22 Mar 2010 07:07:30 +0000</pubDate>
		<dc:creator>andy</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Writing]]></category>

		<guid isPermaLink="false">http://losingfight.com/blog/?p=371</guid>
		<description><![CDATA[Lately it seems there&#8217;s been a lot of talk about distributed version control systems &#8212; especially git and Mercurial &#8212; and how they&#8217;re the bee&#8217;s knees or possibly even the cat&#8217;s pajamas. But at the risk of having my programmer&#8217;s license revoked, I have to confess I don&#8217;t really care about version control systems. I [...]]]></description>
			<content:encoded><![CDATA[<p>Lately it seems there&#8217;s been a lot of talk about distributed version control systems &mdash; especially <a href="http://git-scm.com/">git</a> and <a href="http://mercurial.selenic.com/">Mercurial</a> &mdash; and how they&#8217;re the bee&#8217;s knees or possibly even the cat&#8217;s pajamas.</p>
<p>But at the risk of having my programmer&#8217;s license revoked, I have to confess I don&#8217;t really care about version control systems. I mean, I think it&#8217;s important to use version control, but I don&#8217;t get all excited about the latest ideas in version control technology or the newest VCS on the block. It&#8217;s just a tool. It keeps versions of all my code, and allows me to revert to previous versions, see when and how things changed, and collaborate with other programmers working in the same codebase. Beyond that I don&#8217;t much care.</p>
<p>The tools don&#8217;t make the programmer.</p>
<p>What&#8217;s new with DVCS is the proponents seem to think they need to evangelize their system. Unfortunately they rather suck at it, and their arguments usually leave me feeling that I don&#8217;t want to use software used by such jerks, on account that it might make me into a jerk. Or at least a bigger one.</p>
<p>However, I do think that a DVCS can be a really useful tool so I&#8217;ve come up with some suggestions for those wanting to effectively evangelize their favorite version control system, or at least annoy me less when they talk.</p>
<ol>
<li>
<h2>Don&#8217;t be condescending or insulting</h2>
<p>I think it&#8217;s part of human nature &mdash; or at least programmer nature &mdash; to assume you&#8217;re the smartest guy in the room, and think that anyone who disagrees with you is a real buffon. Programmers seem to take great pleasure in showing that the other person is an idiot, or didn&#8217;t know something they did, or is at least not as clever as they are. A lot of arguments for git or Mercurial seem to revolve around explaining how git or Mercurial are so clearly superior that only morons would use something else.</p>
<p>While this works great for rallying the troops, it&#8217;s counterproductive when trying to win someone over to your side.</p>
<p>Think of it this way: suppose someone comes to your door to tell you about their religion. During the discussion they are self righteous and condescending; they don&#8217;t listen to your arguments, but are only interested in proving that they&#8217;re right. Are you likely to be swayed to believe in their religion? If you&#8217;re like the other hairless bipedal mammals inhabiting this planet you won&#8217;t be, even if they had some valid points.</p>
<p>As soon as you become insulting or condescending, your arguments will be rejected out of hand. I know this will upset some programmers because they believe if you show your argument is superior, everyone will accept it. But that&#8217;s not the way people work.</p>
</li>
<li>
<h2>Try to be helpful</h2>
<p>The best way to introduce someone to your DVCS is by trying to help them. Not in the &#8220;I have all the answers&#8221; way, but in the &#8220;I&#8217;ve dealt with that before, and here&#8217;s what I did&#8221; kind of way. People <em>will</em> run into the kinds of problems that DVCS are good at solving. When they do, you can helpfully suggest a solution.
<p>However, some care should be taken so the suggestion doesn&#8217;t come off the wrong way.</p>
<table>
<tr>
<th>Wrong</th>
<th>Right</th>
</tr>
<tr>
<td>Dude, why are you using subversion?</td>
<td>I&#8217;ve run into that problem before. I solved it by using feature X of git/hg in this way.</td>
<tr>
<td>Dude, just use git/hg.</td>
<td>You smell nice.</td>
</tr>
</table>
<p>Be aware that people may not know where their pain points are. I&#8217;ve seen customers jump through some excruciating hoops to get a piece of software to do something when there was an easier way. People get used to pain and begin to assume it&#8217;s normal. If you notice something like that, even if they&#8217;re not complaining about it, you can politely suggest a better way.</p>
<p>Instead of a list of features that a DVCS provides or abstract arguments as to why they should be using it, people respond better to concrete examples of how a piece of software can make their lives better. People are also more responsive when they know you&#8217;re on their side, trying to help them, even if they don&#8217;t &mdash; or currently can&#8217;t &mdash; take your suggestion. Keep in mind switching VCS in the middle of product cycle is likely something most people can&#8217;t do.</p>
<p>The right attitude is that of trying to help a friend, not conquer an enemy.</p>
</li>
<li>
<h2>Be willing to answer questions, even dumb ones</h2>
<p>Distributed version control works differently from centralized version control, and it does require a different way of thinking. I know I was confused by it when I first started looking into it. A lot of tutorials jump into the mechanics of how to perform certain tasks, but rarely talk about the philosophy of the system or why things are the way they are. If you want to successfully persuade people that your DVCS is the best then you need to be willing to do a lot of patient education.</p>
<p>I say &#8220;patient&#8221; because after using centralized version control they might have difficulty switching over to a new mental model. Or they might have heard a lot of <a href="http://en.wikipedia.org/wiki/Fear,_uncertainty_and_doubt">FUD</a> about your DVCS that you need to put to rest. It&#8217;s important to do this patiently, respectfully, and not insultingly because they&#8217;ve picked up misinformation or don&#8217;t immediately &#8220;get it&#8221; like you do. Otherwise they might ignore your DVCS so they don&#8217;t have to deal with people who look down on them because they don&#8217;t &#8220;get it.&#8221;</p>
</li>
<li>
<h2>Make it trivial to install and use</h2>
<p>This seems like a no brainer, but it is an important part of any software. If it&#8217;s hard to try out and use your DVCS, it simply won&#8217;t get used. I think that for the most part both git and Mercurial succeed in this respect. My only complaint is neither has a good Mac GUI client. Contrast that with Subversion which has both <a href="http://versionsapp.com/">Versions</a> and <a href="http://www.zennaware.com/cornerstone/">Cornerstone</a> on the Mac. You shouldn&#8217;t underestimate the draw of an easy to use, beautiful GUI.</p>
</li>
</ol>
<p>I think <a href="http://www.joelonsoftware.com/">Joel Spolsky</a> has given the best example of how to properly promote and evangelize a DVCS. He wrote a blog post &mdash; <a href="http://www.joelonsoftware.com/items/2010/03/17.html">Distributed Version Control is here to stay, baby</a> &mdash; about how he came to learn and use DVCS. It&#8217;s well written, and instead of condescending, he&#8217;s actually humble and admits he was wrong about DVCS to begin with. Joel also created a site called <a href="http://hginit.com">HgInit</a> that does an amazing job of explaining the philosophy behind Mercurial and gives a solid introduction to right way to use it. It&#8217;s actually the site that convinced me to start using Mercurial for real.</p>
]]></content:encoded>
			<wfw:commentRss>http://losingfight.com/blog/2010/03/22/distributed-version-control-and-other-religions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Compiling OpenCL Kernels with Xcode</title>
		<link>http://losingfight.com/blog/2009/12/17/compiling-opencl-kernels-with-xcode/</link>
		<comments>http://losingfight.com/blog/2009/12/17/compiling-opencl-kernels-with-xcode/#comments</comments>
		<pubDate>Thu, 17 Dec 2009 23:49:44 +0000</pubDate>
		<dc:creator>andy</dc:creator>
				<category><![CDATA[Macintosh]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://losingfight.com/blog/?p=358</guid>
		<description><![CDATA[The talk I&#8217;m working on for NSConference 2010 involves a decent amount of OpenCL kernel code. Originally, I thought I would develop the kernel code the same way I develop Core Image kernel code: build the kernel in Quartz Composer and then copy paste the code into Xcode when I got it working. Unfortunately, I&#8217;ve [...]]]></description>
			<content:encoded><![CDATA[<p>The talk I&#8217;m working on for <a href="http://www.nsconference.com">NSConference 2010</a> involves a decent amount of OpenCL kernel code. Originally, I thought I would develop the kernel code the same way I develop Core Image kernel code: build the kernel in Quartz Composer and then copy paste the code into Xcode when I got it working. </p>
<p>Unfortunately, I&#8217;ve not had much luck with Quartz Composer in way of meaningful compiler errors. Sometimes it returns good errors, sometimes inscrutable ones.</p>
<div align="center">
<a href="/blog/wp-content/uploads/2009/12/QuartzComposer1.png"><img src="/blog/wp-content/uploads/2009/12/QuartzComposer1.png" alt="Quartz Composer" border="0" width="259" height="320" /></a></p>
<div style="font-size:0.7em;">Composer: Wait, wait, I remember this&#8230; it&#8217;s COBOL, right?</div>
</div>
<p>&nbsp;</p>
<p>However, I&#8217;ve found debugging OpenCL kernels to be much easier thanks to the invention of a function I like to call &#8220;printf.&#8221; If you run your kernel on the CPU, then you can print out values just like in C. With debugging solved, I just needed to figure out how to find compiler errors without having to run my code.</p>
<p>Unlike Core Image, OpenCL actually requires you to compile your kernel code explicitly before using it. The API&#8217;s required to do this will return nice compiler error messages and everything. The obvious thing to do would be wrap up these API&#8217;s in a command line tool and invoke the tool from Xcode, which is what I did.</p>
<h2>The Code</h2>
<p>You can download the Xcode project for <a href="/blog/wp-content/uploads/2009/12/clc.zip" title="clc.zip">clc, the OpenCL Compiler here</a>. It requires Mac OS X 10.6 Snow Leopard and the associated Xcode tools. To install, just build the project and copy the resulting binary into your path somewhere. I used ~/bin.</p>
<p>Most of the code is self explanatory, with the possible exception of the output. Unlike most compilers, clc doesn&#8217;t output object code because the host and runtime CPU/GPU&#8217;s could easily be different. It could simply copy the source code as is for the output, but that was a little too obvious for my tastes. Instead clc compresses the source code and stuffs it into a binary plist. It has the slight benefit of potentially being smaller on disk, and making your source code negligibly less accessible to prying eyes, if you&#8217;re into that sort of thing.</p>
<p>There are definite possibilities for improvement. For example, there could be an option to encrypt the source code to be more &#8220;secure.&#8221; Or it could store the binary code generated by the host machine in the output on the chance that the host and runtime machines have the same hardware.</p>
<h2>Setting up Xcode</h2>
<p>To use clc, you&#8217;ll need to set up a build rule in your app&#8217;s target settings to run all OpenCL source files through it. Selecting the menu item Project &gt; Edit Active Target, and then selecting the Rules tab, should land you here:</p>
<p><img src="/blog/wp-content/uploads/2009/12/TargetSettings.png" alt="TargetSettings.png" border="0" width="577" height="306" /></p>
<p>Add another rule, set it to process OpenCL source files using a Custom script. For the custom script enter:</p>
<p><code>~/bin/clc ${INPUT_FILE_PATH} -o ${TARGET_BUILD_DIR}/${PRODUCT_NAME}.app/Contents/Resources/${INPUT_FILE_BASE}.clar</code></p>
<p>Finally, you&#8217;ll need to tell Xcode where you&#8217;re putting the output file, which is:</p>
<p><code>${TARGET_BUILD_DIR}/${PRODUCT_NAME}.app/Contents/Resources/${INPUT_FILE_BASE}.clar</code></p>
<p>By default, Xcode won&#8217;t put OpenCL source files (.cl) into the target, meaning they won&#8217;t get compiled. For each of your OpenCL source files<br />
you&#8217;ll need to explicitly add them to your target. There are several ways to do this, but the easiest is probably selecting all of them, and doing a Get Info (File &gt; Get Info). Switch to the Targets tab and check the target they should be compiled into.</p>
<h2>Runtime Code</h2>
<p>At runtime, it&#8217;s pretty easy to retrieve the original OpenCL source code using the <var>+ (NSString *) openCLSourceWithData:(NSData *)data error:(NSError **)error;</var> method on <var>ONOpenCLArchive</var>. However, there are a couple of convenience methods on NSBundle that makes retrieving the kernel easier. For example:</p>
<p><code></p>
<pre>
#import "ONOpenCLArchive.h"

NSString *kernelSource = [[NSBundle mainBundle] openCLResource:@"MyKernel"];
</pre>
<p></code></p>
<p>That&#8217;s pretty much all there is to it.</p>
<h2>Conclusion</h2>
<p>Although not ground breaking, this little tool has certainly been helpful to me by finding compiler errors at compile time instead of runtime. Hopefully it will be useful to other people as well.</p>
]]></content:encoded>
			<wfw:commentRss>http://losingfight.com/blog/2009/12/17/compiling-opencl-kernels-with-xcode/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>NSConference 2010 Quiz</title>
		<link>http://losingfight.com/blog/2009/12/15/nsconference-2010-quiz/</link>
		<comments>http://losingfight.com/blog/2009/12/15/nsconference-2010-quiz/#comments</comments>
		<pubDate>Wed, 16 Dec 2009 03:49:44 +0000</pubDate>
		<dc:creator>andy</dc:creator>
				<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Macintosh]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://losingfight.com/blog/?p=347</guid>
		<description><![CDATA[For the uninformed, NSConference is a Mac developer&#8217;s conference put on by Scotty &#8220;The Scottster&#8221; Scott and his faithful sidekick, Tim &#8220;The Faithful Sidekick&#8221; Isted. They&#8217;re kind of the Batman and Robin of the Mac programming conference world, but have a slightly lower probability of bat-gassing you than the real dynamic duo. This year they [...]]]></description>
			<content:encoded><![CDATA[<p>For the uninformed, <a href="http://www.nsconference.com">NSConference</a> is a Mac developer&#8217;s conference put on by Scotty &#8220;The Scottster&#8221; Scott and his faithful sidekick, Tim &#8220;The Faithful Sidekick&#8221; Isted. They&#8217;re kind of the Batman and Robin of the Mac programming conference world, but have a slightly lower probability of bat-gassing you than the real dynamic duo.</p>
<p>This year they aren&#8217;t content with bringing conference justice to only the UK, so they&#8217;re branching out to the good &#8216;ole U.S. of A. by way of Atlanta, GA. To help you decide which conference you should attend, US or Europe, I&#8217;ve prepared the following quiz:</p>
<ol>
<li>
<p>What is your opinion of Seattle?</p>
<ol>
<li>It&#8217;s nice, but isn&#8217;t nearly rainy or dreary enough.</li>
<li>I like their coffee.</li>
<li>The residents have too many teeth.</li>
</ol>
</li>
<li>
<p>Describe your driving habits</p>
<ol>
<li>I like to drive on the left side of the road.</li>
<li>I like to drive on both sides of the road.</li>
<li>I like to merge right six lanes without signaling while going 147 mph on the off ramp and giving the finger with both hands in my black Camaro.</li>
</ol>
</li>
<li>
<p>The pinnacle of human achievement is&#8230;</p>
<ol>
<li><a href="http://en.wikipedia.org/wiki/Tea_(meal)">Afternoon tea</a></li>
<li>Sliced bread</li>
<li><a href="http://en.wikipedia.org/wiki/Hee_Haw">Hee Haw</a></li>
</ol>
</li>
</ol>
<p>Scoring: Give yourself -1 points for any <strong>1</strong> answer, 0 points for any <strong>2</strong> answer, and 1 point for any <strong>3</strong> answer.</p>
<p>If you scored is less than zero, you should attend NSConference Europe; if greater than zero, NSConference USA. If you scored exactly zero, you are truly a cultured individual and should attend both.</p>
<p>Personally, I&#8217;ll be attending both, and not just because of peer pressure and insightful quizzes. I&#8217;ll be presenting a talk on how to implement a watercolor brush using Core Image and OpenCL and maybe some duct tape. If you enjoy the graphics articles that I post here, you&#8217;ll probably enjoy my presentation. If not, I hear Steve &#8220;I&#8217;m Batman&#8221; Scott does a mean <a href="http://en.wikipedia.org/wiki/Adam_West">Adam West</a> impression.</p>
]]></content:encoded>
			<wfw:commentRss>http://losingfight.com/blog/2009/12/15/nsconference-2010-quiz/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Implementing AppleScript Recordability</title>
		<link>http://losingfight.com/blog/2009/11/02/implementing-applescript-recordability/</link>
		<comments>http://losingfight.com/blog/2009/11/02/implementing-applescript-recordability/#comments</comments>
		<pubDate>Tue, 03 Nov 2009 05:13:59 +0000</pubDate>
		<dc:creator>andy</dc:creator>
				<category><![CDATA[Macintosh]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://losingfight.com/blog/?p=340</guid>
		<description><![CDATA[For one of my side projects that I&#8217;m currently working on, I decided to implement an AppleScript interface. Designing and implementing one wasn&#8217;t that bad, although Apple&#8217;s AppleScript documentation was sometimes confusing. Fortunately, CocoaDev has a good overview on how to implement AppleScript support. However, one of my frustrations with working with other app&#8217;s AppleScript [...]]]></description>
			<content:encoded><![CDATA[<p>For one of my side projects that I&#8217;m currently working on, I decided to implement an AppleScript interface. Designing and implementing one wasn&#8217;t <em>that</em> bad, although <a href="http://www.red-sweater.com/blog/195/we-need-a-hero">Apple&#8217;s AppleScript documentation was sometimes confusing</a>. Fortunately, CocoaDev has a good <a href="http://www.cocoadev.com/index.pl?HowToSupportAppleScript">overview on how to implement AppleScript support</a>.</p>
<p>However, one of my frustrations with working with other app&#8217;s AppleScript interfaces was trying to figure out how the interface was intended to be used. Sure, the AppleScript Editor would show me all the actions and classes, but it isn&#8217;t always obvious how things are supposed to fit together. Something that would help in these cases is AppleScript recording. I could record the app performing the actions I cared about, then examine how the app itself used the actions and classes. Unfortunately, it seems like only the Finder and <a href="http://www.barebones.com/products/bbedit/">BBEdit</a> ever got around to implementing AppleScript recording.</p>
<p>In the hopes of increasing the number of apps with AppleScript recordability, I&#8217;m going to document my approach to implementing it. For brevity, I&#8217;ll assume you&#8217;ve already an AppleScript interface implemented for your Cocoa app.</p>
<h2>Thinking Big Design Thoughts</h2>
<p>If you have an AppleScript interface for your application, you may think of your app architecture as something like this:</p>
<p><img src="/blog/wp-content/uploads/2009/11/TraditionalModel1.png" alt="Traditional Model for Implementing AppleScript" width="301" height="246" /></p>
<p>Here your AppleScript interface and graphical interface are independent peers, and both modify your model classes directly to accomplish your application&#8217;s tasks. Each interface is separate and largely ignorant of the other.</p>
<p>However, when implementing AppleScript recordability it is helpful to think about your app&#8217;s architecture in a different way:</p>
<p><img src="/blog/wp-content/uploads/2009/11/RecordableModel1.png" alt="Recordable Model for Implementing AppleScript" width="300" height="294" /></p>
<p>In this case the GUI is dependent on, and implemented in terms of, the AppleScript interface. The general guideline is that anything the GUI does that mutates or alters the model goes through the AppleScript interface. However, if the GUI simply needs to access or get information from the model, it would go directly to the model, not through the AppleScript interface. Accessing the model can happen at seemingly random times to the user, and spamming the AppleScript Editor with these accesses when recording only confuses the user.</p>
<p>Suppose an application has table view and a button that deletes the currently selected item in that table view. The table view data source would be implemented the standard way, simply going directly to the model, bypassing the AppleScript layer. However, the delete button, since it alters the model, would be implemented by invoking the AppleScript delete command on the object represented by the current table row.</p>
<p>This design has some other benefits besides recordability. Notably it helps test your AppleScript interface design and implementation. If you find that implementing a GUI feature in terms of your AppleScript interface is impossible or difficult, congratulations, you found a bug! Also, merely testing your GUI also exercises your AppleScript interface. It is not a replacement for testing your AppleScript interface explicitly, but it certainly helps.</p>
<h2>Implementation Hardships</h2>
<p>Everything I&#8217;ve talked about so far hasn&#8217;t been all that novel, and probably has been met with large bucket fulls of &#8220;well, duh&#8221;s by anyone who&#8217;s ever looked into implementing AppleScript recording. The problem isn&#8217;t thinking about how to design in recordability, but actually implementing recordability.</p>
<p>As things stand now, doing something as simple as &#8220;invoking the AppleScript delete command on the object represented by the current table row&#8221; is incredibly involved and painful. You have to manually build up the AppleEvent that represents the delete command and the target model object using functions like <var>AEBuildAppleEvent</var> or classes like <var>NSAppleEventDescriptor</var>. Then you have to remember to target your app by specifying the kCurrentProcess process serial number (specifying kCurrentProcess as the ProcessSerialNumber is currently the only way to enable recording. Bundle identifiers, urls, and pid_t&#8217;s do not work.), and parse the AppleEvent you get back into something useful. You&#8217;d have to do this for <strong>every</strong> property or method on your model object you want exposed for recordability.</p>
<h3>Dreaming of Ponies</h3>
<p>The thing is, the Cocoa runtime has a lot of the AppleScript information from your SDEF file at its disposal and could theoretically generate these interfaces for you. In the ideal hypothetical situation, invoking the delete action via AppleScript inside your app could be as simple as:</p>
<p><code></p>
<pre>
// Suppose ONEmployee is our model object, with the appropriate AppleScript interface implemented
ONEmployee *employee = [_employees objectAtIndex:0];
ONEmployeeASProxy *proxy = employee.appleScriptInterface;
[proxy delete];
</pre>
<p></code></p>
<p>Here, any object that implemented the <var>objectSpecifier</var> method for AppleScript support would automatically get an <var>appleScriptInterface</var> property. The object returned by <var>appleScriptInterface</var> would be a proxy object implementing the same methods and properties as the original object. The proxy object would implement these methods by building up the appropriate AppleEvents, sending them, and parsing the resulting event back into a usable object.</p>
<p>Apple actually gets tantalizingly close to this with the Scripting Bridge. Outside users of your app can run your SDEF file through the <a href="http://developer.apple.com/mac/library/documentation/Darwin/Reference/ManPages/man1/sdp.1.html">sdp</a> command line tool and get a nice Objective-C interface of proxy objects that build, send, and parse AppleEvents to and from your app. However, there is not currently a way tell these proxy objects to target kCurrentProcess, or to initialize one of the proxy objects by passing in a model object that implements <var>objectSpecifier</var>. (I&#8217;ve written this up as <a href="rdar://problem/7359646">rdar://problem/7359646</a>.)</p>
<h3>Harsh Reality</h3>
<p>Since I didn&#8217;t want to wait on Apple to extend the Scripting Bridge to make my life easier, I decided to write a couple of classes to help out. You can <a href="/blog/wp-content/uploads/2009/11/ASObject.zip" title="ASObject.zip">download the code here</a>. The code is under the <a href="/blog/2007/09/05/license-for-sample-code/">MIT license</a>.</p>
<p>The classes work similar to the <var>SBObject</var> and <var>SBElementArray</var> classes in the Scripting Bridge framework. Using these classes, you can invoke the delete AppleScript method like so:</p>
<p><code></p>
<pre>
// Suppose ONEmployee is our model object, with the appropriate AppleScript interface implemented
ONEmployee *employee = [_employees objectAtIndex:0];
[ASObj(employee) invokeCommand:@"delete"];
</pre>
<p></code></p>
<p>The <var>ASObj</var> function creates an <var>ASObject</var> proxy object for any NSObject that implements <var>objectSpecifier</var>. <var>invokeCommand</var> takes care of marshalling the parameters into an AppleEvent, sending it, and unmarshalling the return value into an NSObject. The name of the command is the name of the name used in AppleScript, not the Cocoa implementation.</p>
<p><var>invokeCommand</var> can take parameters, although it gets more tricky:</p>
<p><code></p>
<pre>
ONEmployee *employee = [_employees objectAtIndex:0];
[ASObj(employee) invokeCommand:@"giveRaise" with:[NSNumber numberWithInt:10], @"Percent", nil];
</pre>
<p></code></p>
<p>First, the parameters must be named (it&#8217;s not done by parameter order), and those names must match the Cocoa Key in the SDEF, not the user visible parameter name. Second, the marshalling code (from random NSObjects to AppleEvents) is a bit sparse. I&#8217;ve only added code for the types I needed for my project. If you use it, you may need to add support for other types. The same goes for return values; I only added support for the types that I use.</p>
<p><var>ASObject</var> also has support for properties. For example this marks an employee as exempt:</p>
<p><code></p>
<pre>
ONEmployee *employee = [_employees objectAtIndex:0];
[ASObj(employee) setObject:[NSNumber numberWithBool:YES] forProperty:@"isExempt"];
</pre>
<p></code></p>
<p>The same type restrictions for parameters apply to properties as well. The Cocoa Key for the property must be used here, the same as parameters.</p>
<p>Elements also have basic support, which is where the <var>ASElementArray</var> comes in. Right now the only interesting thing to do with an element array is retrieve a reference to a specific element:</p>
<p><code></p>
<pre>
ONEmployee *employee = [_employees objectAtIndex:0];
ASObject *dependent = [[ASObj(employee) elementForKey:@"dependents"] objectAtIndex:0];
[dependent setObject:[NSNumber numberWithBool:YES] forProperty:@"insured"];
</pre>
<p></code></p>
<p>Unlike other methods, <var>ASElementArray</var>&#8216;s <var>objectAtIndex</var> does not execute an AppleEvents or otherwise take any actions. Instead it constructs an object specifier (i.e. an ASObject) for the given element.</p>
<p>The code is still somewhat rough and incomplete, but should help with anyone wanting to implement AppleScript recording. If nothing else, it should serve as a starting point or sample code for anyone rolling their own solution.</p>
]]></content:encoded>
			<wfw:commentRss>http://losingfight.com/blog/2009/11/02/implementing-applescript-recordability/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>How to implement sharpen and blur tools</title>
		<link>http://losingfight.com/blog/2009/09/17/how-to-implement-sharpen-and-blur-tools/</link>
		<comments>http://losingfight.com/blog/2009/09/17/how-to-implement-sharpen-and-blur-tools/#comments</comments>
		<pubDate>Fri, 18 Sep 2009 05:53:48 +0000</pubDate>
		<dc:creator>andy</dc:creator>
				<category><![CDATA[Core Image]]></category>
		<category><![CDATA[Graphics]]></category>
		<category><![CDATA[Macintosh]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://losingfight.com/blog/?p=212</guid>
		<description><![CDATA[The sharpen and blur tools are simple bitmap tools. They allow you to blur or sharpen parts of an image using a brush metaphor. In addition to being able to control the strength of the sharpen or blur, these tools also typically allow you to control the blend mode when applying the effect. The sharpen [...]]]></description>
			<content:encoded><![CDATA[<p>The sharpen and blur tools are simple bitmap tools. They allow you to blur or sharpen parts of an image using a brush metaphor. In addition to being able to control the strength of the sharpen or blur, these tools also typically allow you to control the blend mode when applying the effect.</p>
<p>The sharpen tool has the following effect on this tweed pattern:</p>
<p><img src="/blog/wp-content/uploads/2009/09/TweedSharpen50.png" alt="Tweed pattern with sharpen applied" width="200" height="200" /></p>
<p>Notice the stripe through the middle where the edges are more strongly defined.</p>
<p>The blur tool has the opposite effect of sharpen on the tweed pattern:</p>
<p><img src="/blog/wp-content/uploads/2009/09/TweedBlur50.png" alt="Tweed pattern with blur applied" width="200" height="200" /></p>
<h2>Implementation Overview</h2>
<p>Like the <a href="/blog/2009/09/16/how-to-implement-a-sponge-tool/">sponge tool</a>, the sharpen and blur tools are subclasses of the <var>FilterBrush</var> class introduced in the <a href="/blog/2007/09/26/how-to-implement-dodge-and-burn-tools/">dodge and burn tutorial</a>. However, unlike sponge, they do require a slight modification to the <var>GenericBrush</var> class to work.</p>
<p>Since almost all of the code in this tutorial has been covered before, I&#8217;ll just highlight the single change to the <var>GenericBrush</var> class, and the new <var>Sharpen</var> and <var>Blur</var> classes. If you want to see everything, <a href="/blog/wp-content/uploads/2009/09/SharpenBlur.zip" title="Sharpen and blur sample code">download the code</a>.</p>
<h2>Changing GenericBrush</h2>
<p>If you recall, at the very beginning of this article I mentioned that sharpen and blur tools typically allow the user to modify the blend mode. This is the blend mode used when stamping the filtered image back on to the original image. <var>GenericBrush</var> contains the code that handles the stamping, so it will need to be modified.</p>
<p>We change the <var>render:at:</var> method for <var>GenericBrush</var> to be:</p>
<p><code>
<pre>
- (void) render:(Canvas *)canvas at:(NSPoint)point
{
	CGContextRef canvasContext = [canvas context];
	CGContextSaveGState(canvasContext);

	CGPoint bottomLeft = CGPointMake( point.x - CGImageGetWidth(mMask) * 0.5, point.y - CGImageGetHeight(mMask) * 0.5 );

	// Our brush has a shape and soft edges. These are replicated by using our
	//	brush tip as a mask to clip to. No matter what we render after this,
	//	it will be in the proper shape of our brush.
	CGRect brushBounds = CGRectMake(bottomLeft.x, bottomLeft.y, CGImageGetWidth(mMask), CGImageGetHeight(mMask));

	CGContextClipToMask(canvasContext, brushBounds, mMask);
	CGContextSetBlendMode(canvasContext, [self blendMode]);
	[self renderInCanvas:canvas bounds:brushBounds at:point];

	CGContextRestoreGState(canvasContext);
}
</pre>
<p></code></p>
<p>The only change made is the call to <var>CGContextSetBlendMode</var> that allows brush subclasses to determine the blend mode to use. The default implementation is simply:</p>
<p><code>
<pre>
- (CGBlendMode) blendMode
{
	return kCGBlendModeNormal;
}
</pre>
<p></code></p>
<p>That&#8217;s it for <var>GenericBrush</var>.</p>
<h2>Sharpen Tool</h2>
<p>The sharpen tool has just two parameters: <var>mMode</var>, which is the blend mode, and <var>mStrength</var> which determines how strong the sharpen effect is applied. They are initialized in <var>init</var> like so:</p>
<p><code>
<pre>
- (id) init
{
	self = [super init];
	if ( self != nil ) {
		// Set the default values for our parameters
		mMode = kCGBlendModeDarken;
		mStrength = 1.0;
	}
	return self;
}
</pre>
<p></code></p>
<p>Here are some examples of the sharpen tool parameters:</p>
<table>
<tr>
<th>mMode</th>
<th>mStrength</th>
<th>Result</th>
</tr>
<tr>
<td>kCGBlendModeNormal</td>
<td>0.5</td>
<td><img src="/blog/wp-content/uploads/2009/09/TweedSharpenNormal50.png" alt="Tweed with sharpen, normal blend mode, 50%" border="0" width="200" height="200" /></td>
</tr>
<tr>
<td>kCGBlendModeNormal</td>
<td>1.0</td>
<td><img src="/blog/wp-content/uploads/2009/09/TweedSharpenNormal100.png" alt="Tweed with sharpen, normal blend mode, 100%" border="0" width="200" height="200" /></td>
</tr>
<tr>
<td>kCGBlendModeDarken</td>
<td>1.0</td>
<td><img src="/blog/wp-content/uploads/2009/09/TweedSharpenDarken100.png" alt="Tweed with sharpen, darken blend mode, 100%" border="0" width="200" height="200" /></td>
</tr>
<tr>
<td>kCGBlendModeLighten</td>
<td>1.0</td>
<td><img src="/blog/wp-content/uploads/2009/09/TweedSharpenLighten100.png" alt="Tweed with sharpen, lighten blend mode, 100%" border="0" width="200" height="200" /></td>
</tr>
</table>
<p>The blend modes typically offered for a sharpen tool are kCGBlendModeNormal, kCGBlendModeDarken, kCGBlendModeLighten, kCGBlendModeHue, kCGBlendModeSaturation, kCGBlendModeColor, and kCGBlendModeLuminosity. In the examples above, kCGBlendModeDarken causes the sharpening to only affect light pixels and kCGBlendModeLighten only affects dark pixels.</p>
<p>The heart of the sharpen tool is the filter it creates. The code for that is:</p>
<p><code>
<pre>
- (CIFilter *) filter
{
	// We need to create and configure our filter here
	CIFilter * filter = [CIFilter filterWithName:@"CIUnsharpMask"];
	[filter setDefaults];
	[filter setValue:[NSNumber numberWithFloat:mStrength * 100.0] forKey:@"inputRadius"];
	return filter;
}
</pre>
<p></code></p>
<p>You&#8217;ll notice that I&#8217;m using the unsharp mask filter to do the sharpening. I should point out that most image editors don&#8217;t use this filter to do the sharpening. Instead, they seem to use a convolution filter to do the sharpening. However, the convolution filter means it is easy for the user to overdue the effect. Unsharp mask does not have that problem, plus unsharp mask is provided by the system.</p>
<p>The final bit of the sharpen tool is returning the correct blend mode:</p>
<p><code>
<pre>
- (CGBlendMode) blendMode
{
	return mMode;
}
</pre>
<p></code></p>
<h2>Blur Tool</h2>
<p>The blur tool is very similar to the sharpen tool. It even takes the same parameters. The only real difference is the filter that it creates, so that&#8217;s what I&#8217;ll present first:</p>
<p><code>
<pre>
- (CIFilter *) filter
{
	// We need to create and configure our filter here.
	CIFilter * filter = [CIFilter filterWithName:@"CIBoxBlur"];
	[filter setDefaults];
	[filter setValue:[NSNumber numberWithFloat:mStrength * 7.0] forKey:@"inputRadius"];

	return filter;
}
</pre>
<p></code></p>
<p>Here I use the built in CIBoxBlur. <var>mStrength</var> ranges from 0 to 1, inclusive. I set the coefficient of 7 simply by trial and error until I got something that &#8220;looked right.&#8221;</p>
<p>Here are some examples of the blur tool:</p>
<table>
<tr>
<th>mMode</th>
<th>mStrength</th>
<th>Result</th>
</tr>
<tr>
<td>kCGBlendModeNormal</td>
<td>0.5</td>
<td><img src="/blog/wp-content/uploads/2009/09/TweedBlurNormal50.png" alt="Tweed with 50% blur, normal blend mode" border="0" width="200" height="200" /></td>
</tr>
<tr>
<td>kCGBlendModeNormal</td>
<td>1.0</td>
<td><img src="/blog/wp-content/uploads/2009/09/TweedBlurNormal100.png" alt="Tweed with 100% blur, normal blend mode" border="0" width="200" height="200" /></td>
</tr>
<tr>
<td>kCGBlendModeDarken</td>
<td>1.0</td>
<td><img src="/blog/wp-content/uploads/2009/09/TweedBlurDarken100.png" alt="Tweed with 100% blur, darken blend mode" border="0" width="200" height="200" /></td>
</tr>
<tr>
<td>kCGBlendModeLighten</td>
<td>1.0</td>
<td><img src="/blog/wp-content/uploads/2009/09/TweedBlurLighten100.png" alt="Tweed with 100% blur, lighten blend mode" border="0" width="200" height="200" /></td>
</tr>
</table>
<h2>Conclusion</h2>
<p>Sharpen and blur are the last of the common filter brushes. Enjoy, and <a href="/blog/wp-content/uploads/2009/09/SharpenBlur.zip" title="Sharpen and blur sample code">download the sample code</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://losingfight.com/blog/2009/09/17/how-to-implement-sharpen-and-blur-tools/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

