Saturday, December 13, 2014

v7

The big feature in v7 is moving elbows. See previous blog post for more details about this. Also included some other minor changes, but nothing particularly noteworthy.

Finding Elbow Positions

Intro

One of the glaring issues with the gunswap animator was the lack of elbow movement. It's fairly easy to calculate the hand positions of a juggler throughout a pattern; they are well defined by the dwell path of the pattern, and when a prop is in flight the hand is just moving towards the next catch. The elbows are a bit trickier though. My goal was to define a function that will return the elbow position given the hand position.

This problem is called "inverse kinematics" and it is fairly well studied. However, a google search on the topic yields papers like this (http://www.ro.feri.uni-mb.si/predmeti/robotizacija/knjiga/inverzna.pdf). As someone who got a C in linear algebra over 7 years ago, I felt a bit in over my head.

Since Juggling Lab has already solved this problem, I decided to sift through their source code. I've used Juggling Lab as a reference for a lot of parts of this project - the bulk of my siteswap syntax is based on the Juggling Lab syntax. After a little searching I found the section of code I was looking for: http://sourceforge.net/p/jugglinglab/code/HEAD/tree/trunk/source/jugglinglab/renderer/Juggler.java#l128.

Unfortunately I was having a hard time following the Juggling Lab code, and didn't want to just start copy/pasting things into gunswap without understanding them. So I sought help from the main developer of Juggling Lab, Jack Boyce. Here's what he had to say:

"If you think about the connection between the shoulder and the hand as a linkage of two stiff pieces (upper arm and lower arm), then the position of the elbow becomes constrained once the hand and shoulder locations are specified. There is only one degree of freedom left, the rotation of the entire arm around the shoulder-hand axis. (Imagine a chicken flapping its wings to show the motion I'm talking about.)"

Up to this point I had been trying to work out complicated solutions considering the individual rotation angles of the shoulder and elbow. However, thinking about the the problem with one degree of freedom - the "chicken wing angle" - was the key to unlocking the solution.

Solution

Below is how I came up with a function getElbowPosition(S,H,l,w,hand) that returns elbow coordinates given inputs for the shoulder position (S), hand position (H), forearm/bicep length (l), "chicken wing" angle (w) and hand. The hand input is just 0/1 (left/right) indicating which direction the chicken wing angle should rotate. A higher chicken wing angle means your elbows are lifted higher. A chicken wing angle of 0 means the plane created by your shoulder/elbow/hand is parallel to the y axis. The juggler in Fig 1. has a high chicken wing angle.
Fig 1.
Fig 2.

Fig 3.

Fig 4.
Below is a step-by-step explanation of the equations in Fig 4.


1) The first step is to transform H to a coordinate system where S is at the origin. This gives a new hand position H'.
2) Another transformation. H'' is the hand position in a coordinate system rotated along the y-axis (the dashed lines in Fig. 2). H'' is a simpler vector to work with because it has a 0 z component.
3) Theta is used to go back to H' from H''. This will be useful later on. Note that in the code I actually use Math.atan2 since Math.atan only goes from -pi/2 to pi/2 and Math.atan2 determines the angle based on the quadrant the input coordinates are in.
4) h is the distance from the shoulder/hand axis to the elbow. This is the height of an isosceles triangle with sides of length l. http://mathworld.wolfram.com/IsoscelesTriangle.html
5) Now we find unit vectors u1 and u2 that are both orthogonal to each other and the shoulder/hand axis. These are simple to find because H'' has a 0 z component.
6) Here is where the chicken wing angle comes into play. This is the position of the elbow as defined by an equation for a circle around the shoulder/hand axis. http://math.stackexchange.com/questions/73237/parametric-equation-of-a-circle-in-3d-space
7) Transforming E'' to E' using theta which we solved for in (3). 
8) Transforming E' to E which is our final result.

Friday, November 14, 2014

Explanation of gunswap code

Here's an explanation of the gunswap code as of v6.0.

Siteswap.js

Siteswap.js is the core siteswap parsing library. It exports 1 function:

CreateSiteswap(siteswapStr [, options])

This function takes a set of inputs describing a siteswap and returns a JSON object with calculated properties of the siteswap.

Inputs

siteswapStr is the only required input and is a siteswap string that adheres to the gunswap notation.

options is a JSON object containing additional options.

Examples

var s1 = CreateSiteswap('531');
var s2 = CreateSiteswap('51',{validationOnly:true});
var s3 = CreateSiteswap('441',{beatDuration:.3,dwellRation:.5});

You don't need to specify all of the options. Here are the list of options and their defaults.

validationOnly: true 
Passing in false will prevent the generation of prop positions and rotations.

numSteps: 1000
Defines the size of the prop positions/rotations arrays. A value of 1000 will calculate the props' positions at 1000 equally spaced steps in the full cycle of the pattern.

beatDuration: .2
Defines the length of a single beat in seconds. A value of .2 will result in a 3 ball cascade with throws lasting .6 seconds.

dwellRatio: .5
Defines the amount of time (as a ratio of the beat duration) the a prop is held between throws. The dwell duration cannot exceed the beat duration, hence it's input as a ratio.

props: [{type: 'ball', radius: .05, C: .95}]
Array of props. Valid types are 'ball', 'club' and 'ring'. Obviously radius and C don't really make any sense for clubs/rings. C if the coefficient of restitution (ie. the bounciness) and is just used for determining the ball path in bounce patterns. If the input array length doesn't match the number of props for the pattern the last object in the array is continuously appended or removed to get a match.

dwellPath: 
This requires more explanation - perhaps another blog post soon.

Return object

The CreateSiteswap function returns a big JSON object with the following properties.

siteswap
The same siteswap string that was provided as an input.

validSyntax
validPattern
multiplex
sync
pass
All of the above are just booleans describing the pattern.

numJugglers
numProps
maxHeight
More fairly simple properties of the siteswap.

tosses
Array of tosses that occur at each beat. 

beats
Siteswap string broken down into its component beats.

states
State array used for pattern validation. See previous blog post.

propOrbits
For each prop an array of throws and what beat they occur at. 

propPositions
Array of x,y,z positions for each prop.

jugglerHandPositions
Array of x,y,z positions for each juggler's hands.

jugglers
Array of jugglers and their x,z positions (y is assumed to be 0).

validationOnly
numSteps
beatDuration
dwellDuration
props
dwellPath
The inputs.

errorMessage
If everything worked, this will be undefined. Otherwise this contains any error messages.

The inner workings of this function are an enigma. But the basic flow is:

1. Validate syntax (http://gunswap.blogspot.com/2014/02/using-regex-to-parse-siteswap-strings.html)
2. Validate pattern (http://gunswap.blogspot.com/2014/03/siteswap-validation.html)
3. Generate prop positions (no post yet)

SiteswapAnimator.js

SiteswapAnimator.js handles all the animation. It exports the SiteswapAnimator class.

Constructor

SiteswapAnimator(containerId)

containerId is the div that the canvas will be appended to. The constructor handles all the scene initialization.

Functions

go(siteswap[,options])

This function runs the animation. siteswap is supposed to be the return object from a call to CreateSiteswap. options is a JSON object containing any animation options. It currently just contains a boolean motionBlur.

zoomIn()
zoomOut()
resize(width,height)
updateAnimationSpeed(animationSpeed)
updateCameraMode(cameraMode)

All of the above function should be fairly obvious. animationSpeed is a value from 0 to 1 where 1 is full speed and 0 is paused. cameraMode is either 'sky' or 'juggler'.

Example

var animator = new SiteswapAnimator('myDiv');
animator.go(SiteswapJS.CreateSiteswap('531'));

index.js

This just instantiates a SiteswapAnimator, reads user inputs, and passes the results of a CreateSiteswap call to the animator.

util.js

This contains general helper code.

v6.0

Quick turnaround on this one, though not much to report. Another new layout for the UI along with the ability to change color/type of individual props. Also added motion blur.

Monday, November 10, 2014

v5.0

Version 5:

- Added support for siteswaps up to "z" (for passing use a capital "P")
- Changed dwell duration to dwell ratio
- Animation automatically starts on page load. If you pass in a siteswap in the URL query string then it'll use that siteswap. For example: ydgunz.github.io/gunswap?siteswap=531. Make sure to encode the URI component (just use encodeURIComponent), so to animate 24[54] you would put in ydgunz.github.io/gunswap?siteswap=%5B33%5D.
- Cubic bezier dwell paths! This is one of the ideas that I've been excited about for a while and it's finally coming together. This will need it's own post to explain everything, but the general idea is that using cubic bezier interpolation to define dwell paths will allow patterns like mills mess, factory, etc. I've added a bezier version of the cascade and the 1-count factory (I think some people call this "waterfall"?) to the hand movement select list. More to come on this.
- I spent some time trying to make more of an app out of this so that folks can save patterns. But I'm not really sure where that's going so I stopped. I think I'm going to spend some time documenting the existing code and figuring out how to clean it up some more. Oh the luxuries of a project with no deadline.

Monday, August 25, 2014

v4.0

Haven't posted in a while. Here's what we've got in v4.0:
  • Separated siteswap parsing/validation from animation and created a Siteswap.js library that can be used both in the browser and on the server with nodejs. I'm hoping to work on some fancier documentation for the Siteswap.js library so that other folks can use it if they are interested.
  • Started using Grunt, Mocha and Travis CI for testing purposes. Grunt is a great Javascript task runner that I really only have set up to watch for changes in the source files and kick off tests, but there's a lot of opportunity there for streamlining some of the development processes. Mocha is the testing framework, pretty simple. Travis CI is an awesome, free, CI platform that runs all my tests on every push to GitHub. 
    • I'm really only testing some of the basic siteswap parsing functionality, but I'm pretty happy with the tests so far. I'm not sure how to go about testing the functionality that generates the prop positions/rotations, will have to give that some more thought. Also need to consider how to test the UI. I've played with Watir in the past, but that's all ruby...
  • Spent a bunch of time playing with a Mongo/NodeJS/Express/EmbeddedJS stack. Considering adding a DB backend so that people can save their patterns. There's a lot to this though and right now I'm still more interested in just the raw animator.
  • Fixed that synchronous halving issue by adding (0,0) to each beat.
  • Introduced a new modifier "S" to change the number of prop rotations in the air and the orientation of the throw and spins (only really applicable to clubs and rings). 
    • The syntax is <toss>S<# of spins><toss orientation><spin orientation>
    • The # of spins represents full 360 degree rotations. This is optional and if it is not present the # of spins will default to floor(<toss>/2). So a toss of 5 would be 2 spins, a toss of 3 would be 1 spin, a toss of 1 would be 0 spins, etc.
    • The toss and spin orientation are defined according to Varkor's notation. http://juggle.wikia.com/wiki/Rotation_notation
    • Examples:
      • 4S04S01S0 - 441 with all flats
      • 5S1XY - 5 cascade with 1 helicopter spin thrown with the club facing in the direction of the positive x axis
  • Number of bounces is now set the same way as the number of spins, ie. 5B1
  • Bounce type now defaults to lift bouncing if you don't specify the bounce type. Thus 5B1 and 5B1L are the same.
  • Changed the pass modifier to be a capital "P".
  • Added a grass texture map to the floor. Easy and fun. 
  • Removed the siteswap explorer and local storage saving option. I think the siteswap explorer deserves to be a separate project and I'll address the saving option when I put a DB backend on this thing.
I know some folks have had trouble with the animator, mostly in Opera and older browser versions. I think I'm going to add a 2-D HTML5 canvas option that doesn't rely on Three.js or WebGL. I've also got a handful of bugs that I should make an effort to log since I haven't actually addressed them yet.

I'm not sure what's next. I know the prop orientation stuff could be way better - more natural angles for club tosses, smoother rotations while the prop is in the dwell path (right now it just jumps), documentation of the syntax. But I'm itching to work on the dwell paths, specifically because I want to try my hand at cubic bezier interpolation. I'd also like to consider more realistic animation of the juggler, but there are a lot of things to consider there. That's a bit more intense on the animation side of things than I think I'm capable of right now.

Sunday, April 6, 2014

v3.0 Released

Just published version 3.0. First thought - what's the difference between 3.1 and 4.0? We have this same debate at work and it seems like there's no real solid answer. I think if my next stopping point only includes some bug fixes and refactoring, then it's 3.1. If it's got a bunch of big new features and (yet another) UI change, then I'll call it 4.0.

Anyways, version 3.0 has the following new features:

  • Improved UI layout
  • Added ring and club prop types
  • Added reverse cascade and shower hand movements
  • Added a "siteswap explorer" that generates vanilla siteswap patterns based on some user inputs
  • Added a save feature using the browser's local storage, so the data wont' persist across browsers and/or machines
I think the next stopping point is going to be a version 3.1 with a bunch of refactoring and bug fixes. There's still that synchronous siteswap "halving" issue and the siteswap explorer doesn't support non-numeric characters. It also kind of gives the user a smoking gun to choke their browser if they generate siteswaps for 8+ beats and max throw height. The help functionality is really lacking, and I think that's because I'm still not sure who the target audience is for this software. If you know your siteswaps and have used something like juggling lab before, then I think this all should be fairly intuitive. If you don't know siteswaps then chances are you're really not interested in this app anyway, so perhaps I don't even try to help that kind of user?

The code is really starting to look like spaghetti. I guess that's the downside to constantly experimenting with different ideas, and not thinking of how the whole thing fits together. I think before I start working on big features for v4.0 (things like customized dwell paths, number of prop rotations in flight, defining where each juggler is in passing patterns) I need to take a step back and re-assess the whole design.

And testing...that didn't last long... I do like the Qunit tests for the siteswap validation component. I think there's some real value to be had there, and I should make sure I spend some time getting that back up to speed. I don't think there's really any sense in automated testing for any of the animation stuff, I'm not even sure how that would work.

Lots of cool stuff here, I'm really pleased with how far this has come since I decided to take the release process more serious. Each release has had its flaws, but actually drawing a line in the sand and saying "this is version 3" feels good.

Monday, March 24, 2014

v2.0 Notes

Reached a good stopping point for v2.0 faster than I expected. I added the following:

  • User inputs for beat duration, dwell duration, prop radius and prop coefficient of restitution (ie. bounciness)
  • Support for bounce juggling
    • Add any number of "B" characters to a single toss to make it a bounce (the number of bounces is the number of B's). Must follow each B with an L (lift), F (force), HL (hyperlift) or HF (hyperforce). So 5 ball lift bounce pattern would be "5BL"
    • http://jugglinglab.sourceforge.net/html/ssnotation.html explains the bounce notation I used
  • Animated jugglers
  • First person camera option
  • User input for animation speed

Priorities for the next version:

  • Synchronous siteswap "halving" issue
  • Alternative dwell paths like reverse cascade, windmill and mills mess
  • Alternative props like clubs and rings
Soon I'd like to write a post about my dwell path and flight path interpolation algorithms. Definitely needs explaining because the code is starting to look a little messy.

Tuesday, March 11, 2014

gunswap v1.0 released!

I am happy to announce that after way too much tinkering and half-complete little scripts, gunswap v1.0 is complete!

All you can do right now is enter a standard siteswap pattern and see it animated in the browser (I've done all my development in Chrome). There is support for vanilla, multiplex, synchronous and passing siteswaps. That lays the groundwork for a lot of cool improvements - what's next?

Version 2 will probably focus mostly on more inputs for configurable parameters. The trick is going to be determining which are the most important. Here are some general categories of input parameters and/or new features:

  • Synchronous siteswap "halving" issue. Consider adding (0,0) in between each beat to make throws match up with async siteswap better.
  • Environment
    • Gravity
    • Beat duration
    • Dwell ratio
  • Props
    • Cosmetic properties like size, shape and color
      • Consider options for different types of props like clubs and rings
    • Coefficient of restitution (if we implement bounce juggling)
  • Toss modifiers
    • Force/lift bounce
    • Rotation of prop (more useful for things like clubs and rings - not really noticeable with balls)
  • Dwell path
    • Current dwell path is just a circle which has options for center, radius and points of catch/release
    • Totally custom dwell paths could be made using some kind of bezier curve algorithm. http://bseth99.github.io/projects/animate/2-bezier-curves.html looks like it has some potential and I think this is how Juggling Lab does it
  • Passing
    • Define juggler positions
    • Allow jugglers to move
  • Animation
    • 2D option
    • Lighting and shading
    • Animation speed
  • Database backend
    • Not sure how interested in this I am, it would be nice to be able to save patterns, but this seems like it would shift the focus of the project

Siteswap validation

In the previous post we discussed validating the format of a siteswap string using regular expressions. However, this is not sufficient for completely validating a siteswap pattern. We need to ensure that all the throws defined by the pattern can be repeated indefinitely without props ever colliding. This can be achieved using state arrays that are frequently associated with siteswaps.

A state diagram will reflect the position of all props at each beat in the pattern. Consider the following state array:

01x23

The state array indicates the time at which each prop is going to land. Prop 0 is landing now. Prop 1 is landing in 1 beat. Prop 2 is landing in 3 beats. Prop 3 is landing in 4 beats. A state diagram should always be the length according to its maximum toss. So if a siteswap has a maximum toss of 7, the state diagrams for that pattern should all be length 7.

Now consider the very basic siteswap 3. We will construct a state array for each beat in the pattern, starting of course when there are no props

3

BEAT 0 NO PROPS xxx
BEAT 1 TOSS 3   xx0
BEAT 2 TOSS 3   x01
BEAT 3 TOSS 3   012
BEAT 4 TOSS 3   120
BEAT 5 TOSS 3   201
BEAT 6 TOSS 3   012
BEAT 7 TOSS 3   120
BEAT 8 TOSS 3   201
...

Notice how beats 3 through 5 could essentially go on forever. This indicates that our siteswap is valid. 

Now let's consider siteswap 531 and try to figure out how we can programmatically identify when we've reached a repeatable set of state arrays.

531

BEAT 0 TOSS 5 xxxx0
BEAT 1 TOSS 3 xx10x
BEAT 2 TOSS 1 210xx

Let's say that a pattern is initialized once all props have been introduced to the pattern and we've completed all of the toss instructions in the siteswap.

BEAT 3 TOSS 5 10xx2
BEAT 4 TOSS 3 0x12x
BEAT 5 TOSS 1 012xx
BEAT 6 TOSS 5 12xx0
BEAT 7 TOSS 3 2x10x
BEAT 8 TOSS 1 210xx
BEAT 9 TOSS 5 10xx2

Let's say that the pattern is complete when we've reached the first throw and we're back at the first state. Thus, our repeatable pattern is the state array represented by beats 3 through 8.

Take note that when a pattern ends in a state where all props are landing sequentially, we'll call this a "ground state" siteswap. This basically just means that you can enter and exit the pattern from the cascade or fountain pattern.

Now consider an excited vanilla siteswap like 51. This siteswap cannot be entered from the ground state and that affects its initialization process.

51

BEAT 0 TOSS 5 xxxx0
BEAT 1 TOSS 1 1xx0x

At this point we would generally toss prop 2 into the mix, but we can't because prop 1 is landing now and needs to be tossed. Thus, we toss prop 1 and save prop 2 for the next beat.

BEAT 3 TOSS 5 xx0x1
BEAT 4 TOSS 1 20x1x - INIT
BEAT 5 TOSS 5 0x1x2
BEAT 6 TOSS 1 01x2x
BEAT 7 TOSS 5 1x2x0
BEAT 8 TOSS 1 12x0x
BEAT 9 TOSS 5 2x0x1
BEAT 10 TOSS 1 20x1x 
BEAT 11 TOSS 5 0x1x2 - COMPLETE

As you can see above, our repeating pattern is beats 5 through 10.

For synchronous siteswaps we need to extend this state model to include left/right hands. Consider (4,4):

(4,4)
LEFT RIGHT
x0   x1
02   13 - INIT
20   31 
02   13
20   31 - COMPLETE

For multiple jugglers we need to extend this state model to include each juggler. Consider <3p|3p>:

<3p|3p>

JUGGLER 1  JUGGLER 2
LEFT RIGHT LEFT RIGHT
xxx  xxx   xxx  xxx
xx1  xxx   xx0  xxx
x1x  xx3   x0x  xx2
1x5  x3x   0x4  x2x - INIT
x5x  3x0   x4x  2x1
5x2  x0x   4x3  x1x
x2x  0x4   x3x  1x5
2x1  x4x   3x0  x5x
x1x  4x3   x0x  5x2
1x5  x3x   0x4  x2x
x5x  3x0   x4x  2x1 - COMPLETE

Finally, consider the multiplex pattern 33[33]. For multiplex patterns we will delimit the landing beats using brackets.

33[33]

JUGGLER 1
LEFT        RIGHT
[x][x][x]   [x][x][x] 
[x][x][0]   [x][x][x] 3
[x][0][x]   [x][x][1] 3
[0][x][2,3] [x][1][x] [33] - init
[x][2,3][x] [1][x][0] 3
[2,3][x][1] [x][0][x] 3
[x][1][x]   [0][x][2,3] [33]
[1][x][0]   [x][2,3][x] 3
[x][0][x]   [2,3][x][1] 3
[0][x][2,3] [x][1][x] [33]
[x][2,3][x] [1][x][x] 3 - complete

So how do you tell when a siteswap is invalid? This occurs when there is a conflict between the number of props landing in a hand and the number of props expected to be tossed by that hand. Consider an invalid siteswap 513.

513

BEAT 0 TOSS 5 [x][x][x][x][0]
BEAT 1 TOSS 1 [1][x][x][0][x]
BEAT 2 TOSS 3 [x][x][0,1][x][x]
BEAT 3 TOSS 5 [x][0,1][x][x][2]
BEAT 4 TOSS 1 ERROR: EXPECTING 1 PROP, 0 LANDING

Monday, February 24, 2014

Using regex to parse siteswap strings

A siteswap is a string that defines a juggling pattern. Explanation of siteswap is out of scope for this post, I'm simply providing additional documentation on how the gunswap Siteswap object parses its input. I think the Juggling Lab documentation has a great page explaining siteswap notation: http://jugglinglab.sourceforge.net/html/ssnotation.html. However, I am not going to consider any of the special extensions they use (at least for now).

Breaking a siteswap down by beats

Every siteswap can be broken down as instructions for a series of beats. Some siteswaps are very simple to break down: 531 is a 5 toss followed by a 3 followed by a 1. However, consider the siteswap (4,4)(4x,4x) which is a relatively long string, but only contains instructions for 2 beats. Each hand throws a 4, then each hand throws a crossing 4. Things can get even more complicated if you consider multiple jugglers, like the siteswap <[33]|(4x,4x)> which only contains instructions for 1 beat: juggler 0 is doing a multiplexed 3 ball cascade and juggler 2 is doing a synchronous 4-ball crossing fountain.

We need to develop a regex that can split any siteswap string into its component beats. So let's start simple.

Vanilla siteswap

TOSS = \d|[a-o]

First consider some simple vanilla siteswaps like 3, 55500, and b97531 (ok maybe this one isn't simple...). All of these siteswaps match the regular expression meaning they can be a digit (\d) or (|) any character "a" through "o" ([a-o]). Note that "a" through "o" really just represent the numbers 10 through 24. We stop at "o" because later on we'll see that "p" is going to be used for something other than representing a toss height.

Multiplexes

MULTIPLEX = \[(\d|[a-g])+\]

Multiplex notation allows us to throw multiple props with the same hand on the same beat. This is handled using brackets. So the siteswap 33[33] is a 4 ball version of the 3 ball cascade where the third throw of the pattern is done with 2 balls following the same path. Let's break down this regex:
  • \[ 
    • starts with a bracket (the bracket needs to be escaped)
  • (\d|[a-g])+ 
    • contains at least 1 of our valid toss expressions
  • \] 
    • ends with a bracket
Synchronous

SYNC = \((TOSS|MULTIPLEX),(TOSS|MULTIPLEX)\)

Now things start to get a little complicated. Consider a synchronous siteswap (4x,4x). This is a synchronous 4-ball fountain where every throw crosses to the other hand. In synchronous siteswap the left side of the comma is the left hand's instructions and the right side is the right hand's instructions. The instructions can be a vanilla toss or a multiplex. Thus, we check for an open and close parentheses with a comma separated vanilla toss or multiplex pattern in between.

You may have noticed that we aren't handling the "x" in (4x,4x). We need to update our TOSS regex to handle that. It is now going to be (\d|[a-g])x?. Note that the question mark means we're looking for 1 or 0 "x" characters following our valid toss pattern. Also note that the "x" character isn't necessarily limited to synchronous siteswap, though its use in vanilla siteswaps is somewhat limited (mostly for transition throws into synchronous).

A valid beat

BEAT = (TOSS|MULTIPLEX|SYNC)

We now have enough regexes to identify valid beats within a pattern, and that's a relatively simple pattern itself. It's simply checking for a vanilla toss, a multiplex, or a sync toss.

This allows us to break even complicated siteswaps into their component beats. Consider the siteswap 5(4,4)[33]. This would be split into: toss a 5, then toss a (4,4), then toss a [33]. While technically not a valid siteswap (we'll see that level of validation later on) it still has a valid siteswap format.

Passing

PASS = <BEAT(\|BEAT)+>

Consider the passing siteswap <3p|3p><3|3> which has two jugglers both running a 3 ball cascade and passing on every other beat. In passing patterns each beat is enclosed between "<" and ">" characters, with each juggler's instructions separated by a "|" character. Each juggler's instructions must be a valid beat, thus we can construct a pass regex solely from the BEAT regex.

Now we need to make another extension to our original vanilla siteswap regex, but only for passing patterns. If we have a 2 juggler passing pattern then we need to look for a "p" appended to any vanilla toss:

(\d|[a-g])x?p?

If there are three or more jugglers then we need a way of determining which juggler the pass is targeted at. This will be denoted by the number immediately following the "p":

(\d|[a-g])x?(p[1-numJugglers])?

Putting it all together

^(PASS)+|(BEAT)+$

The final regex checks to see if you have an entire string composed of any number of passing beats or non-passing beats. That's it! Recall that this does not guarantee the validity of a siteswap, it just ensures the string is a valid format. Later on we will use the concept of state diagrams to determine if a siteswap is valid.

Friday, February 21, 2014

gunswap Version 1 High Level Design

For the past year or so I've been tinkering around with "gswap" - my very own siteswap animator. I think now is time to actually produce something. For starters I'm changing the name to "gunswap" because it sounds cooler.

My goal for version 1 is to produce a simple siteswap animator with 3D graphics and support for synchronous and multiplex siteswaps. This does seem a bit lofty, but I've been tinkering with a siteswap parsing algorithm that I think can support all of these things. Plus the graphics are going to be easy using Three.js.

Out of scope for version 1 is any kind of throw modifier, passing patterns, different kinds of props, etc. I'd like to consider these features when doing the initial design, but they are not going to be present in the first version.

Ok, onto some high level design...

The initial version is going to be a single html page and single js file (plus the necessary js files for Three.js and jQuery and whatever else I end up requiring). No need for a database-backed application quite yet.

Here's a simple overview of what I'm thinking:

function Siteswap(siteswap)
  • Takes in a siteswap string as an input
  • Parses the siteswap and sets the following properties
    • numJugglers
    • numProps
    • maxThrowHeight
    • states - array describing the state of every prop during each beat
    • tossArr - array describing all the tosses in the siteswap
    • propOrbits - array of each prop's path throughout the pattern
  • If the siteswap is invalid we'll throw an appropriate error
function Animator()
  • Instantiates a Siteswap object based on some input from a UI.
  • Generate the prop orbits as an array of positions over time.
  • Run an animation function that draws a scene to the browser looping over the prop orbits. The smaller the step size for the prop orbits the better.

Thursday, February 6, 2014

Hello World!

Welcome to the Gunswap blog!

Gunswap is not a blog about trading firearms. Sorry Second Amendment enthusiasts! This is a blog about computer science and juggling.

Expect posts soon!