Golfed Dragon's Curve

Little dragon’s curve.

I got bored on a rainy Sunday and I thought I would try to mix mathematic and JavaScript.

I love fractals and I saw neat golfed examples of what you can do with the canvas (e.g. this 128 bytes dragon’s curve), so I tried to create a simple dragon’s curve generation visualisation.

My attempt displays splittings of the initial segment as it gradually turns into a curve.


Here is the full code. To make it work, you need a fixed-size canvas whose id is a (demo at the end).

// Canvas properties
c = a.getContext('2d');
W = a.width;
H = a.height;

// Starting points
p=[[W/3,H/3],[2*W/3,2*H/3]];
j=l=i=1;

// Map each key to a number
for(x in c){c[j++]=c[x]}

n=setInterval(_=>{
  // Draw lines
  c[31](0,0,W,H);
  c[34]();
  for(j=l;j--;c[53](p[j][0],p[j][1],1,1));
  c[36]();

  // Create new separation
  p.splice(i,0,
      ((p,b,d)=>[
       .5*(p[0]+b[0]+d*(p[1]-b[1])),
       .5*(p[1]+b[1]+d*(b[0]-p[0])),
      ])(p[i-1],p[i],i%4-2))

  // Update index and length
  i=(i+=2)>++l?1:i;

  // Breakpoint
  l>4000&&clearInterval(n);
})

Let’s break it down:

The first part create variables used during the generation:

  • c the canvas’s context
  • W the canvas’s width
  • H the canvas’s height

All points are vectors, the x is represented with the first element and y with the second. The starting point of the generation is a simple line, going from the first third to the last third of the canvas.

  • j is a general increment value
  • l the length of the curve
  • i the current index in the curve

I use four functions of the canvas’s context: c.clearRect, c.beginPath, c.stroke and c.lineTo. But with the following piece of code I can call c[31], c[34] and so on:

for(x in c){c[j++]=c[x]}

Next we define our interval which will act as the rendering loop. We store it in a variable to be able to stop it later, but this can be omitted.

The first part of the loop draw the current state, all lines between the points.

This erase everything in the canvas, giving us a fresh start.

  c.clearRect(0,0,W,H);

We are drawing a path, i.e. a continuous line on the canvas. Those two instructions start and finish the line.

c.beginPath();
// ...
c.stroke();

Now the fun part, let’s start by decomposing the loop:

for(j = l; j-- > 0;) {
  c.lineTo(p[j][0],p[j][1],1,1);
}

We are iterating through the whole point array, from last to first, creating a new line each time.

The j-- > 0 is simplified to j-- since 0 is falsy.

The c.line part is inserted in the for statement.

We are only generating a new point at a time, in order to produce the growth animation.

To insert a new element in the array at position i, we use the splice method:

p.splice(i,0, new_element)

We call a function that use the current and previous element to generate the new points. d is the direction of the rotation, which alternate between 1 and -1, depending on the current index.

(
  (p,b,d) => [x, y]
)(
  p[i-1],
  p[i],
  i%4-2
)

The new element use the matrix transformation operation (defined here), but simplified to perform both rotation at the same time:

.5*(p[0]+b[0]+d*(p[1]-b[1]))
.5*(p[1]+b[1]+d*(b[0]-p[0]))

The actual formulas are:

xc = 1/2 * ( xa + ya + xb - yb )
yc = 1/2 * ( - xa + ya + xb + yb )

and

xc = 1/2 * ( xa - ya + xb + yb )
yc = 1/2 * ( xa + ya - xb + yb )

Using the d variable we can factor them.

Now we update our variables:

i = (i+=2) > ++l ? 1 : i;
  • l is incremented, since we just added a new point in the array
  • i grow two by two and when it gets bigger than l, it goes back to one

We increment the current index by two because, as we want to proceed the next element in the array, we just added a new one. And we never proceed the first element since the matrix operations are done on the nth and nth-1 elements.

You can try it below (will only work on chrome, see below for more details):


Compatibility note: The name to number hack for the canvas context make this works only on chrome. The other browsers does not have the same ordering.

i.e. with Chrome, Firefox and Safari: compatibility

Using the snippet:

i=0;
for(a in document.createElement('canvas').getContext('2d')){
  console.log(i++, a);
}

You can change de corresponding code with the following:

  c.clearRect c.beginPath c.stroke c.lineTo
Firefox 11 14 16 32
Safari 34 36 47 39

Introduction

One workflow I came across a lot during my programing days is the following:

git status
vi .gitignore
# [Edition ...]
git status
vi .gitignore
# [Edition ...]
git status
git commit

I don’t usually create the best gitignore pattern on the first time, so I need to test multiple times for correctness.

Wait, that seems to be a lot of repetition ! Let’s create a vim plugin !

Git ignore

To check which files are considered by Vim, you can use the git ls-files command.

The options that interest us are:

  • --others: show files that are not tracked by git
  • --ignored: show only ignored files
  • --exclude-from=<file>: read the exclude patterns from the <file>

e.g.

$ git ls-file --others --ignored --exclude-from=.gitignore

This will show all files normally excluded by git, as we read the exclude patterns from the .gitignore file.

Plugin organisation

The plugin is straightforward and runs as follow:

  • Open a new buffer
  • Export the first line as the excluded pattern
  • Insert the excluded files list in the buffer

We choose to create a file in the /tmp folder and to read/write from here. The file path is stored in the s:gitignore_file variable.

Write the pattern

This part is simple as vim provides us the getline function that fetchs the line in the current buffer.

To write it to the gitignore file, we can use the common echo method from bash along with the operator > to override the file.

let l:line = getline(1)
let l:export_command = "echo '".l:line."' > ".s:gitignore_file
call system(l:export_command)

Note: at first I didn’t put enclosing '' to the content of the line. But in zsh, some patterns expanded before writting to the file. e.g. * expanded to all file in the current folder.

Read the excluded files

To read an external command, vim has mutliple solutions. I tried to use the :read! command but I found out the :systemlist was better for my case.

The systemlist command runs a system command and returns its output as a list, whereas the system command returns it as a string. It is more practical to this case because we will get a list of files.

Then to insert it in the document, the setline command can take a list as second argument (the content to be inserted), it is exactly what we need. We can now insert the files at the second line to refresh the document.

let l:gitignore_command = 'git ls-files --others --ignored --exclude-from='.s:gitignore_file
let l:result = systemlist(l:gitignore_command)
call setline(2, l:result)

Clear the file

The last step we need to complete the plugin is to clear the file between reload. The main issue here is to do so without moving the cursor.

The simplest solution is :2,$d, but it changes the cursor position. Instead, we can use the setline command to set blank lines to all lines. Then when inserting the new excluded files, we may have blank line at the end of the file, but at least the cursor don’t move.

To do so we build an array of empty strings to be inserted on all lines from the second line to the last one and insert it with setline.

let l:current_line = 1
let l:last_line = line('$')
let l:reset_lines = []

while l:current_line < l:last_line
  let l:reset_lines += ['']
  let l:current_line += 1
endwhile

call setline(2, l:reset_lines)

Improvements

I already saw some improvements I could make to speed up the process. Building only one array, adding the existing gitignore option to prevent matching files already excluded, … I will consider adding them later.

Result

You can check an example of use here:

asciicast

Please feel free to leave a comment or go see the project on github

Vim Syntax Generator

When you feel like knowing all this syntax stuff, perhaps write a blog post ;)

I may not know everything about the syntax mechanisms in Vim, but at least I’ll share what I understood building a syntax file generator.

Read more ...
208 Energy

Scroll all the way down !

For the release of the new Peugot 208, we developped at Cogit Studio a single scrolling webpage to beautifully present the car.

Feel the energy

The Ad Filter

Tired of seeing boring ads on the internet?

I made something for you …

The Ad Filter1 is a Chrome and Firefox extension that only shows the best ads.

  1. http://www.dandad.org/en/d-ad-browser-ad-filter/