/* eslint-env es6 */
/* global THREE */
(function() {
  'use strict';

  function createPoints( string ) {
    const lines = string.split( '\n' );

    const points = [];
    for ( let i = 0; i < lines.length; i++ ) {
      const line = lines[i].trim();

      if ( !line.length ) {
        continue;
      }

      const point = line.split( ' ' ).map( parseFloat );

      if ( !point.length || point.some( isNaN ) ) {
        continue;
      }

      const [ x, y = x ] = point;
      points.push( new THREE.Vector2( x, y ) );
    }

    return points;
  }

  // SVG path operations.
  // [operation name, offset to point position].
  const ops = {
    // M x y
    M: [ 'moveTo' ],
    // L x y
    L: [ 'lineTo' ],
    // Q x1 y1 x y
    Q: [ 'quadraticCurveTo', 2 ],
    // C x1 y1 x2 y2 x y
    C: [ 'bezierCurveTo', 4 ],
  };

  const relativeOps = {
    // m dx dy
    m: [ 'moveTo' ],
    // l dx dy
    l: [ 'lineTo' ],
    // q dx1 dy2 dx dy
    q: [ 'quadraticCurveTo', 2 ],
    // c dx1 dt1 dx2 dt2 dx dt
    c: [ 'bezierCurveTo', 4 ],
  };

  function createPathPoints( string ) {
    const lines = string.split( '\n' );

    const path = new THREE.Path();
    for ( let i = 0; i < lines.length; i++ ) {
      let line = lines[i].trim();

      if ( !line.length ) {
        continue;
      }

      let opcode;
      // Does this line start with an opcode?
      if ( /^[A-Za-z]/.test( line ) ) {
        opcode = line.slice( 0, 1 );
        line = line.slice( 1 ).trim();
      }

      const point = line.split( ' ' ).map( parseFloat );

      if ( !point.length || point.some( isNaN ) ) {
        continue;
      }

      // moveTo.
      if ( !i ) {
        path.moveTo( ...point );
      }

      // Absolute path commands.
      else if ( ops[ opcode ] ) {
        const op = ops[ opcode ];
        path[ op[0] ]( ...point );
      }

      // Relative path commands.
      else if ( relativeOps[ opcode ] ) {
        const op = relativeOps[ opcode ];

        // Convert each tuple to absolute coordinates.
        const absolutePoint = point.map( ( n, index ) => {
          return n + path.currentPoint.getComponent( index % 2 );
        });

        path[ op[0] ]( ...absolutePoint );
      }
    }

    return path.getPoints();
  }

  window.createPoints = createPoints;
  window.createPathPoints = createPathPoints;
}());

@@ -583,57 +583,8 @@
 ns.%0A
-  // %5Boperation name, offset to point position%5D.%0A
   co
@@ -614,18 +614,16 @@
 y%0A    M:
- %5B
  'moveTo
@@ -615,34 +615,32 @@
 %0A    M: 'moveTo'
- %5D
 ,%0A    // L x y%0A 
@@ -644,18 +644,16 @@
 y%0A    L:
- %5B
  'lineTo
@@ -645,34 +645,32 @@
 %0A    L: 'lineTo'
- %5D
 ,%0A    // Q x1 y1
@@ -680,18 +680,16 @@
 y%0A    Q:
- %5B
  'quadra
@@ -692,37 +692,32 @@
 adraticCurveTo',
- 2 %5D,
 %0A    // C x1 y1 
@@ -732,18 +732,16 @@
 y%0A    C:
- %5B
  'bezier
@@ -741,37 +741,32 @@
 'bezierCurveTo',
- 4 %5D,
 %0A  %7D;%0A%0A  const r
@@ -801,18 +801,16 @@
 y%0A    m:
- %5B
  'moveTo
@@ -806,26 +806,24 @@
  m: 'moveTo'
- %5D
 ,%0A    // l d
@@ -833,18 +833,16 @@
 y%0A    l:
- %5B
  'lineTo
@@ -842,18 +842,16 @@
 'lineTo'
- %5D
 ,%0A    //
@@ -873,18 +873,16 @@
 y%0A    q:
- %5B
  'quadra
@@ -897,13 +897,8 @@
 To',
- 2 %5D,
 %0A   
@@ -931,18 +931,16 @@
 t%0A    c:
- %5B
  'bezier
@@ -952,13 +952,8 @@
 To',
- 4 %5D,
 %0A  %7D
@@ -1724,27 +1724,24 @@
     path%5B op
-%5B0%5D
  %5D( ...point
@@ -2084,11 +2084,8 @@
 %5B op
-%5B0%5D
  %5D( 

Simplify SVG-based path operations.