<?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; Macintosh</title>
	<atom:link href="http://losingfight.com/blog/category/macintosh/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>Announcing Skyscraper</title>
		<link>http://losingfight.com/blog/2012/05/21/announcing-skyscraper/</link>
		<comments>http://losingfight.com/blog/2012/05/21/announcing-skyscraper/#comments</comments>
		<pubDate>Mon, 21 May 2012 20:37:25 +0000</pubDate>
		<dc:creator>andy</dc:creator>
				<category><![CDATA[Fortunate Bear]]></category>
		<category><![CDATA[Macintosh]]></category>
		<category><![CDATA[Skyscraper]]></category>

		<guid isPermaLink="false">http://losingfight.com/blog/?p=547</guid>
		<description><![CDATA[I&#8217;m happy to announce that I&#8217;ve acquired Pandora from Positive Spin Media, and renamed it Skyscraper in order to reduce confusion with the music service. Skyscraper is a web scraper specializing in finding and downloading images. It can take advantage of Google Image Search to do keyword searches or simply scrape images (or other kinds [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m happy to announce that I&#8217;ve acquired Pandora from <a href="http://positivespinmedia.com/">Positive Spin Media</a>, and renamed it Skyscraper in order to reduce confusion with the music service. <a href="http://fortunatebear.com/products/skyscraper/">Skyscraper is a web scraper</a> specializing in finding and downloading images. It can take advantage of Google Image Search to do keyword searches or simply scrape images (or other kinds of files) from a URL that you give to it. It automatically downloads the images into folders and allows you to perform some simple management. It also has a built-in slide show.</p>
<p>Skyscraper has a <a href="http://fortunatebear.com/products/skyscraper/download/">free limited trial</a>, so there&#8217;s no reason not to give it a try. Skyscraper is free for existing Pandora customers, otherwise $29.99 for new customers.</p>
<p>You can read more about <a href="http://prmac.com/release-id-42997.htm">the acquisition in the press release</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://losingfight.com/blog/2012/05/21/announcing-skyscraper/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Illuminate 1.2 Overhauls the Window Switching UI</title>
		<link>http://losingfight.com/blog/2012/05/09/illuminate-1-2-overhauls-the-window-switching-ui/</link>
		<comments>http://losingfight.com/blog/2012/05/09/illuminate-1-2-overhauls-the-window-switching-ui/#comments</comments>
		<pubDate>Wed, 09 May 2012 17:15:52 +0000</pubDate>
		<dc:creator>andy</dc:creator>
				<category><![CDATA[Fortunate Bear]]></category>
		<category><![CDATA[Illuminate]]></category>
		<category><![CDATA[Macintosh]]></category>

		<guid isPermaLink="false">http://losingfight.com/blog/?p=539</guid>
		<description><![CDATA[Illuminate 1.2 is out with major changes to how the cycle windows feature works. Since cycle windows is the main feature in Illuminate, I made an effort to streamline it and make it usable in fewer keystrokes. The most noticeable change is that Cycle (All) Windows and Cycle (All) Tabs have been consolidated into one [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://fortunatebear.com/products/illuminate/">Illuminate 1.2</a> is out with major changes to how the cycle windows feature works. Since cycle windows is the main feature in Illuminate, I made an effort to streamline it and make it usable in fewer keystrokes. The most noticeable change is that Cycle (All) Windows and Cycle (All) Tabs have been consolidated into one feature: Cycle Windows. Cycle Windows cycles through all the windows and tabs using just one keyboard shortcut (Option-Tab), plus they&#8217;re now grouped by application, making application switching more obvious.</p>
<p><img src="http://losingfight.com/blog/wp-content/uploads/2012/05/Screenshot1.png" alt="Screenshot1" border="0" width="600" height="375" /></p>
<p>In order to speed up switching between windows, sticky mode has be turned off by default so the window selection happens as soon as you let up on the modifier keys. Also, there is now a configurable delay between when the keyboard shortcut is pressed and the UI shows up. This means you can quickly switch between windows or tabs without the UI flashing up or otherwise having to wait on it.</p>
<p>The 1.2 includes some other features and bug fixes:</p>
<ul>
<li>
<p>Support for Google Chrome tabs</p>
</li>
<li>
<p>Ability to exclude certain applications from the window switching list.</p>
</li>
<li>
<p>You can now change the order windows appear in when switching windows: last time accessed or alphabetical.</p>
</li>
<li>
<p>Improved layout in the cycle windows UI so more space is used by the window thumbnails.</p>
</li>
<li>
<p>Fix for a crashing bug.</p>
</li>
</ul>
<p>The update is free for existing customers, $9.99 for new customers, and is available from <a href="http://fortunatebear.com/products/illuminate/buy/">Fortunate Bear&#8217;s online store</a> or <a href="http://itunes.apple.com/us/app/illuminate/id504770329?ls=1&#038;mt=12">Apple&#8217;s Mac App Store</a>.</p>
<p>You can <a href="http://prmac.com/release-id-42459.htm">read the full press release here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://losingfight.com/blog/2012/05/09/illuminate-1-2-overhauls-the-window-switching-ui/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Log Leech 1.5 updates Mac version, introduces iOS version</title>
		<link>http://losingfight.com/blog/2012/04/03/log-leech-1-5-updates-mac-version-introduces-ios-version/</link>
		<comments>http://losingfight.com/blog/2012/04/03/log-leech-1-5-updates-mac-version-introduces-ios-version/#comments</comments>
		<pubDate>Tue, 03 Apr 2012 20:11:50 +0000</pubDate>
		<dc:creator>andy</dc:creator>
				<category><![CDATA[Fortunate Bear]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Log Leech]]></category>
		<category><![CDATA[Macintosh]]></category>

		<guid isPermaLink="false">http://losingfight.com/blog/?p=535</guid>
		<description><![CDATA[A new version of Log Leech is out today. It updates the Mac version by doing some UI clean up, improving HTML export, adding a log entry detail view, and improving performance and stability. In addition, version 1.5 introduces a universal iOS version of the app. The iOS version is quite similar to the Mac [...]]]></description>
			<content:encoded><![CDATA[<p>A new version of <a href="http://fortunatebear.com/products/log-leech/">Log Leech</a> is out today. It updates the Mac version by doing some UI clean up, improving HTML export, adding a log entry detail view, and improving performance and stability. In addition, version 1.5 introduces a universal iOS version of the app. The iOS version is quite similar to the Mac version; the main difference is instead of providing an export function, it allows you to email the logs to the address of your choice.</p>
<p>The 1.5 release for Mac is free for existing customers, and $9.99 for new customers. It can be found either in <a href="http://fortunatebear.com/products/log-leech/buy/">Fortunate Bear&#8217;s online store</a> or <a href="http://itunes.apple.com/us/app/log-leech/id502729076?ls=1&#038;mt=12">Apple&#8217;s Mac App Store</a>. The iOS version is $4.99, and can be found in the <a href="http://itunes.apple.com/us/app/log-leech/id513351119?ls=1&#038;mt=8">App Store</a>.</p>
<p>See the <a href="http://prmac.com/release-id-40617.htm">press release</a> for more information.</p>
]]></content:encoded>
			<wfw:commentRss>http://losingfight.com/blog/2012/04/03/log-leech-1-5-updates-mac-version-introduces-ios-version/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Big Bag of App Store Bugs</title>
		<link>http://losingfight.com/blog/2012/03/27/big-bag-of-app-store-bugs/</link>
		<comments>http://losingfight.com/blog/2012/03/27/big-bag-of-app-store-bugs/#comments</comments>
		<pubDate>Tue, 27 Mar 2012 23:19:24 +0000</pubDate>
		<dc:creator>andy</dc:creator>
				<category><![CDATA[Apple]]></category>
		<category><![CDATA[Bugs]]></category>
		<category><![CDATA[Fortunate Bear]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Macintosh]]></category>

		<guid isPermaLink="false">http://losingfight.com/blog/?p=532</guid>
		<description><![CDATA[I&#8217;ve been meaning to write about some of the major problems that I have with the App Store, both the Mac and iOS varieties. But honestly, I don&#8217;t have a whole lot to add to what Wil Shipley and Craig Hockenberry have already said. Instead, I&#8217;ll link to the bugs I&#8217;ve written up, and encourage [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been meaning to write about some of the major problems that I have with the App Store, both the Mac and iOS varieties. But honestly, I don&#8217;t have a whole lot to add to what <a href="http://blog.wilshipley.com/2012/03/mac-app-store-needs-paid-upgrades.html">Wil Shipley</a> and <a href="http://furbo.org/2009/07/10/year-two/">Craig Hockenberry</a> have already said. Instead, I&#8217;ll link to the bugs I&#8217;ve written up, and encourage you to do the same.</p>
<ul>
<li>
<p>The App Stores need to support upgrade pricing. <a href="rdar://11131356">rdar://11131356</a> or <a href="http://openradar.appspot.com/11131356">Open Radar</a></p>
</li>
<li>
<p>The App Stores need to support free trials. <a href="rdar://11133210">rdar://11133210</a> or <a href="http://openradar.appspot.com/11133210">Open Radar</a></p>
</li>
<li>
<p>The App Stores need to support tracking statistics. <a href="rdar://11133330">rdar://11133330</a> or <a href="http://openradar.appspot.com/11133330">Open Radar</a></p>
</li>
<li>
<p>The App Stores need better discoverability of apps. <a href="rdar://11133573">rdar://11133573</a> or <a href="http://openradar.appspot.com/11133573">Open Radar</a></p>
</li>
</ul>
<p>I know there&#8217;s been a lot of pessimism about writing up Radars lately, <a href="/blog/2012/01/30/our-engineers-are-aware-of-the-issue/">including from yours truly</a>. But the truth is filing bugs is the only official way Apple will listen, so the pragmatic side of me wins out. It&#8217;s not that I necessarily think filing bugs will cause a change, but it&#8217;s the only possible way of affecting changing that&#8217;s been given to me.</p>
]]></content:encoded>
			<wfw:commentRss>http://losingfight.com/blog/2012/03/27/big-bag-of-app-store-bugs/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fortunate Bear Acquires Pagehand, renames it Pagesmith</title>
		<link>http://losingfight.com/blog/2012/03/27/fortunate-bear-acquires-pagehand-renames-it-pagesmith/</link>
		<comments>http://losingfight.com/blog/2012/03/27/fortunate-bear-acquires-pagehand-renames-it-pagesmith/#comments</comments>
		<pubDate>Tue, 27 Mar 2012 18:15:07 +0000</pubDate>
		<dc:creator>andy</dc:creator>
				<category><![CDATA[Fortunate Bear]]></category>
		<category><![CDATA[Macintosh]]></category>
		<category><![CDATA[Pagesmith]]></category>

		<guid isPermaLink="false">http://losingfight.com/blog/?p=529</guid>
		<description><![CDATA[If you follow me on Twitter, then you know that I&#8217;ve acquired Pagehand from Ross Carter (a.k.a. Pagehand.com), and renamed it Pagesmith. Pagesmith is a unique word processor that focuses on writing and typography. You can check out the product page here for more details. I&#8217;m particularly excited about this acquisition because Pagesmith is the [...]]]></description>
			<content:encoded><![CDATA[<p>If you follow me on Twitter, then you know that I&#8217;ve acquired Pagehand from Ross Carter (a.k.a. Pagehand.com), and renamed it Pagesmith. Pagesmith is a unique word processor that focuses on writing and typography. You can <a href="http://fortunatebear.com/products/pagesmith/">check out the product page here</a> for more details.</p>
<p>I&#8217;m particularly excited about this acquisition because Pagesmith is the first really &#8220;deep&#8221; app that I have. I can&#8217;t wait to spend some quality time with it, growing it into something even better. In addition, I really love the direction Ross started Pagesmith off in: a focus on creating beautiful documents through typography and an innovative, clutter free UI.</p>
<p>Anyway, you can read more about the transition in the <a href="http://prmac.com/release-id-40280.htm">press release</a>. And don&#8217;t forget to <a href="http://fortunatebear.com/products/pagesmith/">give the free 30-day trial a go</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://losingfight.com/blog/2012/03/27/fortunate-bear-acquires-pagehand-renames-it-pagesmith/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Illuminate 1.1 is out</title>
		<link>http://losingfight.com/blog/2012/03/19/illuminate-1-1-is-out/</link>
		<comments>http://losingfight.com/blog/2012/03/19/illuminate-1-1-is-out/#comments</comments>
		<pubDate>Mon, 19 Mar 2012 18:36:23 +0000</pubDate>
		<dc:creator>andy</dc:creator>
				<category><![CDATA[Fortunate Bear]]></category>
		<category><![CDATA[Illuminate]]></category>
		<category><![CDATA[Macintosh]]></category>

		<guid isPermaLink="false">http://losingfight.com/blog/?p=525</guid>
		<description><![CDATA[Illuminate 1.1 is out now. It&#8217;s a small feature update including: Support for cycling through tabs, although its currently limited to Safari tabs. As you&#8217;re cycling through windows, the tabs will appear beneath the windows. A complete, in application help file explaining all the features Illuminate provides. A new front end application to manage the [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://fortunatebear.com/products/illuminate/">Illuminate 1.1</a> is out now. It&#8217;s a small feature update including:</p>
<ul>
<li>
<p>Support for cycling through tabs, although its currently limited to Safari tabs. As you&rsquo;re cycling through windows, the tabs will appear beneath the windows.</p>
</li>
<li>
<p>A complete, in application help file explaining all the features Illuminate provides.</p>
</li>
<li>
<p>A new front end application to manage the preferences. This prevents the preferences window from getting lost behind all the other windows. It also now shows up in Illuminate itself.</p>
</li>
</ul>
<p>It&#8217;s a free update for existing customers, US$9.99 for new customers. Version 1.1 is also the first version you can find in <a href="http://itunes.apple.com/us/app/illuminate/id504770329?mt=12">Apple&#8217;s Mac App Store</a>. You can <a href="http://prmac.com/release-id-39581.htm">read the entire press release</a> if you&#8217;d like.</p>
]]></content:encoded>
			<wfw:commentRss>http://losingfight.com/blog/2012/03/19/illuminate-1-1-is-out/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fortunate Bear Acquires Creastoric</title>
		<link>http://losingfight.com/blog/2012/02/27/fortunate-bear-acquires-creastoric/</link>
		<comments>http://losingfight.com/blog/2012/02/27/fortunate-bear-acquires-creastoric/#comments</comments>
		<pubDate>Mon, 27 Feb 2012 20:45:59 +0000</pubDate>
		<dc:creator>andy</dc:creator>
				<category><![CDATA[Fortunate Bear]]></category>
		<category><![CDATA[Log Leech]]></category>
		<category><![CDATA[Macintosh]]></category>

		<guid isPermaLink="false">http://losingfight.com/blog/?p=519</guid>
		<description><![CDATA[Today I completed the acquisition of another small software company, Creastoric. If you don&#8217;t know, Creastoric was the creator of Log Leech, an application that has an innovative way of viewing and navigating system logs. If you&#8217;re the kind of person who needs to deal with logs, I encourage you to check it out. I [...]]]></description>
			<content:encoded><![CDATA[<p>Today I completed the acquisition of another small software company, Creastoric. If you don&#8217;t know, Creastoric was the creator of <a href="http://fortunatebear.com/products/log-leech/">Log Leech</a>, an application that has an innovative way of viewing and navigating system logs. If you&#8217;re the kind of person who needs to deal with logs, I encourage you to check it out.</p>
<p>I think the product (as a system utility) fits well with my existing Mac product, <a href="http://fortunatebear.com/products/illuminate/">Illuminate</a>. Both are kind of power user products, and I&#8217;m hoping there is some overlap in the audience. Either way, it&#8217;s exciting to see my product portfolio expand. I have a lot planned for Log Leech and Illuminate.</p>
<p>Anyway, you can get all the details of the acquisition in the <a href="http://prmac.com/release-id-38939.htm">press release</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://losingfight.com/blog/2012/02/27/fortunate-bear-acquires-creastoric/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>New Product Preview, Kind of</title>
		<link>http://losingfight.com/blog/2012/01/05/new-product-preview-kind-of/</link>
		<comments>http://losingfight.com/blog/2012/01/05/new-product-preview-kind-of/#comments</comments>
		<pubDate>Thu, 05 Jan 2012 22:13:24 +0000</pubDate>
		<dc:creator>andy</dc:creator>
				<category><![CDATA[Fortunate Bear]]></category>
		<category><![CDATA[Macintosh]]></category>
		<category><![CDATA[Vectorspring]]></category>

		<guid isPermaLink="false">http://losingfight.com/blog/?p=508</guid>
		<description><![CDATA[I&#8217;ve been hard at work on Fortunate Bear&#8217;s next product, but I wanted to lift my head long enough to give a quick preview of what I&#8217;m working on. Keep in mind, it&#8217;s very early in development and maybe 20% (if that) of the features are done. But without further ado: (Video is HTML 5, [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been hard at work on Fortunate Bear&#8217;s next product, but I wanted to lift my head long enough to give a quick preview of what I&#8217;m working on. Keep in mind, it&#8217;s very early in development and maybe 20% (if that) of the features are done. But without further ado:</p>
<p><video controls><br />
 <source src="http://losingfight.com/videos/VectorspringPreview1.m4v" type="video/mp4" /> <!-- MPEG4 for Safari --><br />
 <source src="http://losingfight.com/videos/VectorspringPreview1.ogg" type="video/ogg" /> <!-- Ogg Theora for Firefox 3.1b2 --></p>
<p></video></p>
<p>(Video is HTML 5, so you&#8217;ll need a recent browser.)</p>
<p>As a bonus you get to see my fantastical art skills. The codename for the project is Vectorspring, and I hope to be showing off more as it progresses.</p>
]]></content:encoded>
			<wfw:commentRss>http://losingfight.com/blog/2012/01/05/new-product-preview-kind-of/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
<enclosure url="http://losingfight.com/videos/VectorspringPreview1.m4v" length="2244793" type="video/mp4" />
<enclosure url="http://losingfight.com/videos/VectorspringPreview1.ogg" length="2456376" type="audio/ogg" />
		</item>
		<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>
	</channel>
</rss>

