Category Archives: geek

Exploring neighbourhood libraries and other notes from the Toronto Public Library Hackathon

UPDATE 2015-11-27: Here’s the video of my hackathon pitch:

UPDATE 2015-11-18: I figured out how to make this entirely client-side, so you don’t have to run a separate server. First, install either Tampermonkey (Chrome) or Greasemonkey (Firefox). Then install the user script insert-visualize-link.user.js , and the Visualize link should appear next to the library branch options on Toronto Public Library search result pages. See the Github repository for more details.

Yay! My neighbourhood library visualization won at the Toronto Public Library hackathon. It added a Visualize link to the search results page which mapped the number of search results by branch. For example, here’s a visualization of a search that shows items matching “Avengers comics“.


It’s a handy way to see which branches you might want to go to so that you can browse through what’s there in person.

Librarians could also use it to help them plan their selections, since it’s easy to see the distribution across branches. For example, here’s the visualization for books in Tagalog.


The collections roughly match up with Wellbeing Toronto‘s data on Tagalog as the home language, although there are some areas that could probably use collections of their own.

tagalog census

Incidentally, I was delighted to learn that Von Totanes had done a detailed analysis of the library’s Filipino collections in the chapter he wrote in Filipinos in Canada: Disturbing Invisibility (Coloma, McElhinny, and Tungohan, 1992). Von sent me the chapter after I mentioned the hackathon on Facebook; yay people bumping into other people online!

Personally, I’m looking forward to using this visualization to see things like which branches have new videos. Videos released in the past year can only be borrowed in person – you can’t request them online – so it’s good to check branches regularly to see if they’re there. It would be even better if the library search engine had a filter for “On the shelf right now”, but in the meantime, this visualization tool gives me a good idea of our chances of picking up something new to watch while we’re folding laundry. =)


More notes will probably follow, but here are a few quick drawings:

2015-11-15b Tech - Exploring neighbourhood libraries -- index card #tpl #hackathon

2015-11-15b Tech – Exploring neighbourhood libraries – index card #tpl #hackathon

2015-11-15c Kaizen and the Toronto Public Library hackathon -- index card #tpl #hackathon #kaizen #improvement

2015-11-15c Kaizen and the Toronto Public Library hackathon – index card #tpl #hackathon #kaizen #improvement

2015-11-15d Other reflections from TPL hackathon -- index card #tpl #hackathon #introversion #prototyping #presenting

2015-11-15d Other reflections from TPL hackathon – index card #tpl #hackathon #introversion #prototyping #presenting

2015-11-15e Ideas for following up on TPL hackathon -- index card #prototyping #tpl #hackathon

2015-11-15e Ideas for following up on TPL hackathon – index card #prototyping #tpl #hackathon


The code works by extracting the branch names and totals on the left side of search pages and combining those with the locations of the branches (KML). I don’t really need the server component, so I’m thinking of rewriting the script so that it runs entirely client-side – maybe as a Chrome extension or as a user script. That way, other people can play with the idea without running their own server (and without my having to keep a server around), and we can try it out without waiting for the library to integrate it into their website. That said, it would be totally awesome to get it into the interface of the Toronto Public Library! We’ll just have to see if it can happen. =) Happy to chat with library geeks to get this sorted out.

It was fun working on this. W- decided to join me at the last minute, so it turned into a fun weekend of hanging out with my husband at the library. I wanted to keep my weekend flexible and low-key, so I decided not to go through the team matchmaking thing. W- found some comfy chairs in the corner of the area, I plugged in the long extension cord I brought, and we settled in.

I learned a lot from the hackathon mentors. In particular, I picked up some excellent search and RSS tips from Alan Harnum. You can’t search with a blank query, but he showed me how you can start with a text string, narrow the results using the facets on the left side, and then remove the text string from the query in order to end up with a search that uses only the facets. He also showed me that the RSS feed had extra information that wasn’t in the HTML source and that it could be paginated with URL parameters. Most of the RSS feeds I’d explored in the past were nonpaginated subsets of the information presented on the websites, so it was great to learn about the possibilities I had overlooked.

The faceted search was exactly what I needed to list recent videos even if I didn’t know what they were called, so I started thinking of fun tools that would make hunting for popular new videos easier. (There have been quite a few times when I’ve gone to a library at opening time so that I could snag a video that was marked as available the night before!) In addition to checking the specific item’s branch details to see where it was on the shelf and which copies were out on loan, I was also curious about whether we were checking the right library, or if other libraries were getting more new videos than our neighbourhood library was.

W- was curious about the Z39.50 protocol that lets you query a library catalogue. I showed him the little bits I’d figured out last week using yaz-client from the yaz package, and he started digging into the protocol reference. He figured out how to get it to output XML (format xml) and how to search by different attributes. I’m looking forward to reading his notes on that.

Me, I figured that there might be something interesting in the visualization of new videos and other items. I hadn’t played around a lot with geographic visualization, so it was a good excuse to pick up some skills. First, I needed to get the data into the right shape.

Step 1: Extract the data and test that I was reading it correctly

I usually find it easier to start with the data rather than visualizations. I like writing small data transformation functions and tests, since they don’t involve complex external libraries. (If you miss something important when coding a visualization, often nothing happens!)

I wrote a function to extract information from the branch CSV on the hackathon data page, using fast-csv to read it as an array of objects. I tested that with jasmine-node. Tiny, quick accomplishment.

Then I worked on extracting the branch result count from the search results page. This was just a matter of finding the right section, extracting the text, and converting the numbers. I saved a sample results page to my project and used cheerio to parse it. I decided not to hook it up to live search results until I figured out the visualization aspect. No sense in hitting the library website repeatedly or dealing with network delays.

Step 2: Make a simple map that shows library branches

I started with the Google Maps earthquake tutorial. The data I’d extracted had addresses but not coordinates. I tried using the Google geocoder, but with my rapid tests, I ran into rate limits pretty early. Then it occurred to me that with their interest in open data, the library was the sort of place that would probably have a file with branch coordinates in terms of latitude and longitude. The hackathon data page didn’t list any obvious matches, but a search for Toronto Public Library KML (an extension I remembered from W-‘s explorations with GPS and OpenStreetMap) turned up the file I wanted. I wrote a test to make sure this worked as I expected.

Step 3: Combine the data

At first I tried to combine the data on the client side, making one request for the branch information and another request for the results information. It got a bit confusing, though – I need to get the hang of using require in a from-scratch webpage. I decided the easiest way to try my idea out was to just make the server combine the data and return the GeoJSON that the tutorial showed how to visualize. That way, my client-side HTML and JS could stay simple.

Step 4: Fiddle with the visualization options

Decisions, decisions… Red was too negative. Blue and green were hard to see. W- suggested orange, and that worked out well with Google Maps’ colours. Logarithmic scale or linear scale? Based on a maximum? After experimenting with a bunch of options, I decided to go with a linear scale (calculated on the server), since it made sense for the marker for a branch with a thousand items to be significantly bigger than a branch with five hundred items. I played with this a bit until I came up with maximum and minimum sizes that made sense to me.

Step 5: Hook it up to live search data

I needed to pass the URL of the search results, and I knew I wanted to be able to call the visualization from the search results page itself. I used TamperMonkey to inject some Javascript into the Toronto Public Library webpage. The library website didn’t use JQuery, so I looked up the plain-vanilla Javascript way of selecting and modifying elements.

  .parentNode.querySelector('h3').innerHTML =
  'Library Branch <a target="_blank" style="color: white; ' +
  'text-decoration: underline" ' +
  'href="http://localhost:9000/viz.html?url=' +
  encodeURIComponent(location.href) + '">(Visualize)</a>';

Step 6: Tweak the interface

I wanted to display information on hover and filter search results on click. Most of the tutorials I saw focused on how to add event listeners to individual markers, but I eventually found an example that showed how to add a listener to and get the information from the event object. I also found out that you could add a title attribute and get a simple tooltip to display, which was great for confirming that I had the data all lined up properly.

Step 7: Cache the results

Testing with live data was a bit inconvenient because of occasional timeouts from the library website, so I decided to cache search results to the filesystem. I didn’t bother writing code for checking last modification time, since I knew it was just for demos and testing.

Step 8: Prettify the hover

The tooltip provided by title was a little bare, so I decided to spend some time figuring out how to make better information displays before taking screenshots for the presentation. I found an example that showed how to create and move an InfoWindow based on the event’s location instead of relying on marker information, so I used that to show the information with better formatting.

Step 9: Make the presentation

Here’s how I usually plan short presentations:

  1. Figure out the key message and the flow.
  2. Pick a target words-per-minute rate and come up with a word budget.
  3. Draft the script, checking it against my word budget.
  4. Read the script out loud a few times, checking for time, tone, and hard-to-say phrases.
  5. Annotate the script with notes on visual aids.
  6. Make visuals, take screenshots, etc.
  7. Record and edit short videos, splitting them up in Camtasia Studio by using markers so that I can control the pace of the video.
  8. Copy the script (or keywords) into the presenter’s notes.
  9. Test the script for time and flow, and revise as needed.

I considered two options for the flow. I could start with the personal use case (looking for new videos) and then expand from there, tying it into the library’s wider goals. That would be close to how I developed it. Or I could start with one of the hackathon challenges, establish that connection with the library’s goals, and then toss in my personal use case as a possibly amusing conclusion. After chatting about it with W- on the subway ride home from the library, I decided to start with the second approach. I figured that would make it easier for people to connect the dots in terms of relevance.

I used ~140wpm as my target, minus a bit of a buffer for demos and other things that could come up, so roughly 350 words for 3 minutes. I ran through the presentation a few times at home, clocking in at about 2:30. I tend to speak more quickly when I’m nervous, so I rehearsed with a slightly slower pace. That way, I could get a sense of what the pace should sound like. During the actual presentation, though, I was a teensy bit over time – there was a bit of unexpected applause. Also, even though I remembered to slow down, I didn’t breathe as well as I probalby should’ve; I still tend to breathe a little shallowly when I’m on stage. Maybe I should pick a lower WPM for presentations and add explicit breathing reminders. =)

I normally try to start with less material and then add details to fit the time. That way, I can easily adjust if I need to compress my talk, since I’ve added details in terms of priority. I initially had a hard time concisely expressing the problem statement and tying together the three examples I wanted to use, though. It took me a few tries to get things to fit into my word budget and flow in a way that made me happy.

Anyway, once I sorted out the script, I came up with some ideas for the visuals. I didn’t want a lot of words on the screen, since it’s hard to read and listen at the same time. Doodles work well for me. I sketched a few images and created a simple sequence. I took screenshots for the key parts I wanted to demonstrate, just in case I didn’t get around to doing a live demo or recording video. That way, I didn’t have to worry about scrambling to finish my presentation. I could start with something simple but presentable, and then I could add more frills if I had time.

Once the static slides were in place, I recorded and edited videos demonstrating the capabilities. Video is a nice way to give people a more real sense of how something works without risking as many technical issues as a live demo would.

I had started with just my regular resolution (1366×768 on my laptop) and a regular browser window, but the resulting video was not as sharp as it could have been. Since the presentation template had 4:3 aspect ratio, I redid the video with 1024×768 resolution and a full-screen browser in order to minimize the need for resizing.

I sped up boring parts of the video and added markers where I wanted to split it into slides. Camtasia Studio rendered the video into separate files based on my markers. I added the videos to individual slides, setting them to play automatically. I like the approach of splitting up videos onto separate slides because it allows me to narrate at my own pace instead of speeding up or slowing down to match the animation.

I copied the segments of my script to the presenter notes for each slide, and I used Presenter View to run through it a few more times so that I could check whether the pace worked and whether the visuals made sense. Seemed all right, yay!

Just in time, too. I had a quick lunch and headed off to the library for the conclusion of the hackathon.

There wsa a bit of time before the presentations started. I talked to Alan again to show him what I’d made, hear about what he had been working on, and pick his brain to figure out which terms might resonate with the internal jargon of the library – little things, like what they call the people who decide what kinds of books should be in which libraries, or what they call the things that libraries lend. (Items? Resources? Items.) Based on his feedback, I edited my script to change “library administrators” to “selection committees”. I don’t know if it made a difference, but it was a good excuse to learn more about the language people used.

I tested that the presentation displayed fine on the big screen, too. It turned out that the display was capable of widescreen input at a higher resolution than what I’d set, but 1024×768 was pretty safe and didn’t look too fuzzy, so I left it as it was. I used my presentation remote to flip through the slides while confirming that things looked okay from the back of the room (colours, size, important information not getting cut off by people’s heads, etc.). The hover text was a bit small, but it gave the general idea.

And then it was presentation time. I was third, which was great because once I finished, I could focus on other people’s presentations and learn from their ideas. Based on W-‘s cellphone video, it looks like I remembered to use the microphone so that the library could record, and I remembered to look up from my presenter notes and gesture from time to time (hard when you’re hidden behind the podium, but we do what we can!). I stayed pretty close to my script, but I hope I kept the script conversational enough that it sounded more like me instead of a book. I didn’t have the mental bandwidth to keep an eye on the timer in the center of the presenter view, but fortunately the time worked out reasonably well. I concluded just as the organizer was getting up to nudge me along, and I’d managed to get to all the points I wanted to along the way. Whew!

Anyway, that’s a quick braindump of the project and what it was like to hack it together. I’ll probably write some more about following up on ideas and about other people’s presentations, but I wanted to get this post out there while the experience was fresh in my head. It was fun. I hope the Toronto Public Library will take the hackathon ideas forward, and I hope they’ll get enough out of the hackathon that they’ll organize another one! =)

2015-11-09 Emacs News

Links from, Hacker News,, Youtube, and the Emacs commit log.

Past Emacs News round-ups

Capturing links quickly with emacsclient, org-protocol, and Chrome Shortcut Manager on Microsoft Windows 8

Since I’ll be snipping lots of Emacs-related resources and organizing them into Emacs news roundups, I figured it was time to get org-protocol working.

Step 1: Get emacsclient to work

I was getting the error “No connection could be made because the target machine actively refused it.” I needed to change my Windows Firewall rules. From the Windows Firewall screen, I clicked on Advanced settings and chose Inbound Rules. On the Programs and Services tab, I confirmed that the right Emacs binary was selecI looked for the rules for GNU Emacs, consolidating them down to two rules (UDP and TCP). I limited the scope to local/remote On the advanced tab, I selected all the profiles and changed edge traversal to blocked.

I was still getting the error despite a fresh M-x server-start. After I deleted the contents of ~/.emacs.d/server and did another M-x server-start. When I ran emacsclient test.txt from the command-line, it correctly opened the file in my existing Emacs instance. Hooray!

Step 2: Load org-protocol

I added org-protocol to the org-modules variable so that Org would load it when Emacs reaches the (org-load-modules-maybe t) in my config. Since I didn’t want to restart Emacs, I also evaluated (load-library "org-protocol") to load it.

Step 3: Register the protocol

I ran an org-protocol.reg that set up the appropriate org protocol entry:

Windows Registry Editor Version 5.00

"URL Protocol"=""
@="URL:Org Protocol"



@="\"c:\\Program Files (x86)\\GNU Emacs 24.4\\bin\\emacsclientw.exe\"  \"%1\""

You can find a similar one in the org-protocol documentation.

Step 4: Add support to Chrome

I wanted something a bit different from the org-capture extensions available for Chrome. In particular, I wanted:

  • a keyboard-friendly way to quickly store a link
  • a keyboard-friendly way to capture a link with some notes

The Shortcut Manager extension for Chrome lets you specify your own keyboard shortcuts for running short Javascript. Inline Javascript doesn’t work on all sites. For example, Github blocks it with the following error: Refused to execute inline script because it violates the following Content Security Policy directive: "script-src". Either the 'unsafe-inline' keyword, a hash ('...'), or a nonce ('nonce-...') is required to enable inline execution. Still, it works for many sites, so it’s a start. Here are the shortcuts I put together.

l Store link
L Store link (prompt for title, default to selection or document title)
c Capture link (prompt for template)

You can import them by going to Chrome’s More Tools > Extensions screen and choosing the Options link for Shortcut Manager. From there, use Import settings.

// ==UserScript==
// @ShortcutManager
// @name Store link
// @namespace XPrUJhE4wRsC
// @key l
// @include *
// ==/UserScript==
var storeLink = function(){
  var selection = window.getSelection().toString();
  var uri = 'org-protocol://store-link://' +
        encodeURIComponent(window.location.href) + '/' +
        encodeURIComponent(selection || document.title);
  window.location = uri;
  return uri;

// ==UserScript==
// @ShortcutManager
// @name Capture link
// @namespace XPrUJhE4wRsC
// @key c
// @include *
// ==/UserScript==
var captureLink =function(){
  var uri = 'org-protocol://capture://' +
        encodeURIComponent(window.location.href) + '/' +
        encodeURIComponent(document.title) + '/' +
  window.location = uri;
  return uri;

// ==UserScript==
// @ShortcutManager
// @name Store link with prompt
// @namespace XPrUJhE4wRsC
// @key Shift+l
// @include *
// ==/UserScript==
var storeLinkWithPrompt = function(){
  var selection = window.getSelection().toString();
  var uri = 'org-protocol://store-link://' +
        encodeURIComponent(window.location.href) + '/' +
        encodeURIComponent(window.prompt('Title', selection || document.title));
  window.location = uri;
  return uri;

Shortcut Manager looks like a really useful extension. Here are some other shortcuts I set up:

x close the current tab
r reload (cacheless)
t open a new tab
n select the right tab
p select the left tab
b back
f forward

Step 5: Add shortcuts for managing stored links

I added my/org-insert-link and org-insert-last-stored-link to my main hydra, which is on my hh keychord. my/org-insert-link is like org-insert-link, except it adds a newline if the cursor is at an Org link so that we don’t trigger org-insert-link‘s behaviour of editing links.

(defun my/org-insert-link ()
  (when (org-in-regexp org-bracket-link-regexp 1)
    (goto-char (match-end 0))
    (insert "\n"))
  (call-interactively 'org-insert-link))

(key-chord-define-global "hh"
                         (defhydra my/key-chord-commands ()
                           ;; ...
                           ("L" my/org-insert-link)
                           ("l" org-insert-last-stored-link)
                           ;; ...

This lets me quickly insert a bunch of links with a key sequence like h h l l l l or select a link to insert with h h L. C-y (yank) pulls in the URL of the last stored link, too.

Let’s see how this works out!

2015-11-02 Emacs News

Previous roundup – Links from,, and Youtube

Python + sewing: Making basic shapes and splitting up larger patterns

More Python and sewing. =) The first step was to make parameterization even easier by allowing command-line specification of measurements. I refactored some code from and modified mkpattern to accept the new arguments, splitting up the name and value based on regular expressions (commit). That way, I could quickly generate patterns based on different dimensions, like so:

python ../mkpattern --client=../customer/Sacha/sacha-cm.json \
   --pattern=../patterns/ \
   --styles=../tests/test_styles.json \
   -m height=4in -m width=7.5in -m seam_allowance=0.5in \
   -m depth=7.5in -m strap_width=1in -m strap_length=10in -m hem_allowance=1in \

I sketched basic patterns for cylindrical and box-type containers the other day, so I wanted to try them out. It turned out that the Python framework I used for sewing patterns didn’t yet support arcs. Adding the arc element to the SVG was straightforward. I initially faked the bounding box for the arc, but since that made the code misbehave a little, I looked around for a better implementation. I translated the code from this post from 2011 to Python and added it to the code (git commit). That allowed me to make a simple cylinder pattern generator. I haven’t tested it yet, but it looks reasonable.

2015-10-27 20_30_11-foo.svgThe box tote was interesting to work on. When I did the math, I couldn’t believe that the calculations were that simple. I was waiting for a sqrt or a cos to show up, I think. Still, the small-scale paper version I taped up looks like it makes sense, and I’ll sew a full-size version soon. J- asked for a light blue lunch bag that would fit our standard containers, and I’ve been meaning to make a casserole carrier for a while now. It would be handy to be able to make bags that are the right size. Too small and things don’t lie flat, too big and they move around too much.

2015-10-27 20_31_54-foo.svg - Inkscape

I spent most of my time making a flexible circle skirt pattern, pretzeling my brain around circumferences, angles, multiple pieces, and fullness multipliers. I’m happy with the way it turned out. It can generate patterns for quarter-circle skirts, half-circle skirts, full-circle skirts – even an arbitrary fraction of skirt fullness split into an arbitrary number of pieces, with optional seam allowance, waist seam allowance, and hem allowance. If you give it the fabric width, it will split the pattern into however many pieces are needed. If you specify a seam allowance and you want a full-circle skirt in a single piece (maybe for dolls), it’ll leave room for the seam allowances by adjusting the inner radius. We’re heading into snow pants season, so I probably won’t get around to testing it in fabric for a while. Caveat netrix, I guess.

I also got around to writing a tool for splitting up large patterns so that I could print them on a regular printer. I had tried Posterazor and a few other tools for splitting up large images into smaller pages, but I wanted something that would add cutting lines and page numbers. It turns out that all you need to do is change the SVG’s height, width, and viewPort. I added a rectangle for the cutting line and some text for the page numbers. I haven’t figured out how to use pysvg to replace the contents of an existing text element, but since the tool prints out non-overlapping regions, I just keep adding more text elements. My script creates a numbered sequence of SVGs. I haven’t found a convenient way to print multiple SVGs in one go, but I can select multiple PNGs and print those, and I can use Inkscape’s command line to convert SVGs to PNGs like so:

inkscape -z -e output-01.png -d 300 output-01.svg

There’s supposed to be a -p command to output Postscript ready for printing, but command-line printing on Windows doesn’t seem to be as much of a thing as it is on Linux. Something to figure out another time, maybe. Anyway, now that I have a conversion pipeline, I can write a Bash script or Emacs Lisp to process things automatically.

I’ll probably move from all this theoretical script-writing to more hands-on sewing during the rest of the week. My fabric order has arrived, so I’ve got a bit of cutting and sewing ahead of me.

Hmm. With the command-line measurement and scaling overrides, it might be interesting to use this framework for papercraft and laser-cutting too. Someday!

Programmatically rescaling and manipulating the darts in sewing patterns

I’ve been playing with the tmtp project for programmatically generating SVGs based on body measurements in order to create basic blocks and sewing patterns (see my previous blog post). I’m not yet at the point of being able to look at an image and see if it will sew correctly. However, printing and taping up large patterns is frustrating and a waste of paper. Scaling the patterns down so that they fit on a single page of paper makes perfect sense. With the measurements I’m working with, a scale of 0.2 (1″ : 5″) makes things fit neatly on 8.5″x11″ paper. It’s easy enough to cut them out and tape them up into something that resembles the form.

Here’s the commit that adds the scaling factor, and the commit that adds a very useful --scale command-line option. This lets me do something like this:

python mkpattern --verbose \
  --client=customer/Sacha/sacha-cm.json \
  --pattern=patterns/ \
  --styles=tests/test_styles.json --scale=0.2 output.svg

I generated a bunch of SVGs using my measurements, printed and cut them, and taped them up. Tada! They look like they make sense. The easy-fitting bodice block from Metric Pattern Cutting is, as expected, looser than the close-fitting bodice block, and both are a little bit bigger than the basic bodice block from BurdaStyle.

2015-10-26 16.17.312015-10-26 16.20.17

The basic shirt pattern from Cal Patch’s Design-it-Yourself Clothes fits over the basic blocks, as expected. It looks a little boxy compared to the blocks, but it will probably be fine in cotton, since cotton won’t be as stiff as paper.

2015-10-26 16.18.49

If I end up doing this a lot, I’ll probably look into modifying the patterns to draw an outline on a separate layer. Then I can convert the SVG for use with Hacklab’s laser cutter (see my previous experiments and fun results), so I can easily test with paper or fabric.

I was thinking about the viability of printing a small, to-scale 3D model based on measurements. Doesn’t have to be a photorealistic 3D scan of me – apparently you can get photorealistic 3D prints for about ~$120 these days, but that’s still a bit much. If it’s not from a scan, though, there’s the challenge of generating a good model based on entered measurements, or creating/adjusting an existing model of a dress maker’s mannequin. Anyway, papercraft with basic blocks seems to be a decent starting point. =)

With the scaling factor in place, I did the math for dart manipulation. Darts help add shape to fabric, turning flat pieces into slightly conical structures. If you wanted to move a dart on paper, you could tape the dart closed, then cut a new line to the apex of the dart and spread the pattern until it’s flat again. (Wikipedia describes this as slash-and-spread.)

There’s an SVG rotate transformation that would probably make it easier to handle the rotation of complex shapes. I haven’t figured out how to add an SVG group in tmtp yet, though. Instead, I:

  1. Added a pair of points where my “cut” was going to be
  2. Calculated the existing dart angle
  3. Rotated one of the dart points, one of the new cut points, and the points in between – to make things easier, I specified which points to rotate
  4. Redrew the front bodice

I added a few library functions, so now the code to rotate a dart is pretty short. It takes an array defining the dart points (start, apex, end), and another array of the points to rotate around the apex by the calculated angle.

def rotateDart(self, dart_points, points_to_rotate):
    # Determine the angle of rotation
    angle = angleOfVectorP(dart_points[0], dart_points[1], dart_points[2])
    # Rotate the dart closed
    (dart_points[0].x, dart_points[0].y) = rotateP(dart_points[0], dart_points[1], angle)
    # Rotate the rest of the points
    for i in range(len(points_to_rotate)):
        (points_to_rotate[i].x, points_to_rotate[i].y) = rotateP(points_to_rotate[i], dart_points[1], angle)

When I printed out my test pattern and cut it, the new pattern matched the result of slashing and spreading the dart on the previous bodice. Hooray for paper testing!

2015-10-26 18.27.54

The next step would probably be to make an SVG slicer that converts large patterns into segments that can be printed on a home printer. It would probably move/clip the image, add cutting lines and labels for convenience, and export a series of SVGs. If I’m lucky, I might be able to find a Python library that will let me easily create a multi-page PDF.

More thoughts on sewing and programming: it would be nifty to be able to easily program variable seam allowances, so that I could say that one seam has a 1/2″ allowance and the other has a 2″ hem allowance. Lines should be pretty straightforward – just offset a parallel line by the specified distance. Bezier curves might be a challenge. In “An offset algorithm for polyline curves” (Liu, Yong, Zheng, and Sun, 2006), the authors describe a algorithm involving trimming the offset curves of a polyline curve. I should check out the approximation algorithms mentioned in their literature review – might be an easier thing to start with, especially if I can wrap my head around the way the existing code’s curveLength function interpolates curves. Or I can leave the addition of variable allowances as a human step. It’s not that hard with a seam allowance ruler. Still, it would be neat to have laser-ready SVGs… =)

Anyway, now that I’ve got a simple way to test things on a small scale and a bit more of a handle on the math, I’m looking forward to playing around with generating actual patterns instead of just basic blocks. Whee!