From a81e7b7916c9f753b8c9367b901a0ddfc3aa30e7 Mon Sep 17 00:00:00 2001 From: Mugen87 Date: Wed, 3 Feb 2021 12:25:23 +0100 Subject: [PATCH] SVGLoader: New parseFloats() implementation. --- examples/js/loaders/SVGLoader.js | 224 ++++++++++++++++++++++++++++-- examples/jsm/loaders/SVGLoader.js | 224 ++++++++++++++++++++++++++++-- 2 files changed, 424 insertions(+), 24 deletions(-) diff --git a/examples/js/loaders/SVGLoader.js b/examples/js/loaders/SVGLoader.js index bd36c16bb30cba..7d0b3c18227030 100644 --- a/examples/js/loaders/SVGLoader.js +++ b/examples/js/loaders/SVGLoader.js @@ -973,35 +973,235 @@ THREE.SVGLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype } - function parseFloats( string ) { + // from https://github.com/ppvg/svg-numbers (MIT License) - var array = string.split( /[\s,]+|(?=\s?[+\-])/ ); + function parseFloats( input ) { - for ( var i = 0; i < array.length; i ++ ) { + if ( typeof input !== 'string' ) { - var number = array[ i ]; + throw new TypeError( 'Invalid input: ' + typeof input ); - // Handle values like 48.6037.7.8 - // TODO Find a regex for this + } + + // Character groups + var RE = { + SEPARATOR: /[ \t\r\n\,.\-+]/, + WHITESPACE: /[ \t\r\n]/, + DIGIT: /[\d]/, + SIGN: /[-+]/, + POINT: /\./, + COMMA: /,/, + EXP: /e/i + }; + + // States + var SEP = 0; + var INT = 1; + var FLOAT = 2; + var EXP = 3; + + var state = SEP; + var seenComma = true; + var result = [], number = '', exponent = ''; + + function throwSyntaxError( current, i, partial ) { + + var error = new SyntaxError( 'Unexpected character "' + current + '" at index ' + i + '.' ); + error.partial = partial; + throw error; + + } + + function newNumber() { + + if ( number !== '' ) { + + if ( exponent === '' ) result.push( Number( number ) ); + else result.push( Number( number ) * Math.pow( 10, Number( exponent ) ) ); + + } + + number = ''; + exponent = ''; + + } + + var current, i = 0, length = input.length; + for ( i = 0; i < length; i ++ ) { + + current = input[ i ]; + + // parse until next number + if ( state === SEP ) { + + // eat whitespace + if ( RE.WHITESPACE.test( current ) ) { + + continue; + + } + + // start new number + if ( RE.DIGIT.test( current ) || RE.SIGN.test( current ) ) { + + state = INT; + number = current; + continue; + + } + + if ( RE.POINT.test( current ) ) { + + state = FLOAT; + number = current; + continue; + + } + + // throw on double commas (e.g. "1, , 2") + if ( RE.COMMA.test( current ) ) { + + if ( seenComma ) { + + throwSyntaxError( current, i, result ); + + } + + seenComma = true; + + } + + } + + // parse integer part + if ( state === INT ) { + + if ( RE.DIGIT.test( current ) ) { + + number += current; + continue; + + } + + if ( RE.POINT.test( current ) ) { + + number += current; + state = FLOAT; + continue; + + } + + if ( RE.EXP.test( current ) ) { - if ( number.indexOf( '.' ) !== number.lastIndexOf( '.' ) ) { + state = EXP; + continue; - var split = number.split( '.' ); + } + + // throw on double signs ("-+1"), but not on sign as separator ("-1-2") + if ( RE.SIGN.test( current ) + && number.length === 1 + && RE.SIGN.test( number[ 0 ] ) ) { + + throwSyntaxError( current, i, result ); + + } + + } + + // parse decimal part + if ( state === FLOAT ) { + + if ( RE.DIGIT.test( current ) ) { + + number += current; + continue; + + } - for ( var s = 2; s < split.length; s ++ ) { + if ( RE.EXP.test( current ) ) { - array.splice( i + s - 1, 0, '0.' + split[ s ] ); + state = EXP; + continue; + + } + + // throw on double decimal points (e.g. "1..2") + if ( RE.POINT.test( current ) && number[ number.length - 1 ] === '.' ) { + + throwSyntaxError( current, i, result ); } } - array[ i ] = parseFloatWithUnits( number ); + // parse exponent part + if ( state == EXP ) { + + if ( RE.DIGIT.test( current ) ) { + + exponent += current; + continue; + + } + + if ( RE.SIGN.test( current ) ) { + + if ( exponent === '' ) { + + exponent += current; + continue; + + } + + if ( exponent.length === 1 && RE.SIGN.test( exponent ) ) { + + throwSyntaxError( current, i, result ); + + } + + } + + } + + + // end of number + if ( RE.WHITESPACE.test( current ) ) { + + newNumber(); + state = SEP; + seenComma = false; + + } else if ( RE.COMMA.test( current ) ) { + + newNumber(); + state = SEP; + seenComma = true; + + } else if ( RE.SIGN.test( current ) ) { + + newNumber(); + state = INT; + number = current; + + } else if ( RE.POINT.test( current ) ) { + + newNumber(); + state = FLOAT; + number = current; + + } else { + + throwSyntaxError( current, i, result ); + + } } - return array; + // add the last number found (if any) + newNumber(); + return result; } diff --git a/examples/jsm/loaders/SVGLoader.js b/examples/jsm/loaders/SVGLoader.js index e0b0062f1fce08..94e8d9e8b774d0 100644 --- a/examples/jsm/loaders/SVGLoader.js +++ b/examples/jsm/loaders/SVGLoader.js @@ -985,35 +985,235 @@ SVGLoader.prototype = Object.assign( Object.create( Loader.prototype ), { } - function parseFloats( string ) { + // from https://github.com/ppvg/svg-numbers (MIT License) - var array = string.split( /[\s,]+|(?=\s?[+\-])/ ); + function parseFloats( input ) { - for ( var i = 0; i < array.length; i ++ ) { + if ( typeof input !== 'string' ) { - var number = array[ i ]; + throw new TypeError( 'Invalid input: ' + typeof input ); - // Handle values like 48.6037.7.8 - // TODO Find a regex for this + } + + // Character groups + var RE = { + SEPARATOR: /[ \t\r\n\,.\-+]/, + WHITESPACE: /[ \t\r\n]/, + DIGIT: /[\d]/, + SIGN: /[-+]/, + POINT: /\./, + COMMA: /,/, + EXP: /e/i + }; + + // States + var SEP = 0; + var INT = 1; + var FLOAT = 2; + var EXP = 3; + + var state = SEP; + var seenComma = true; + var result = [], number = '', exponent = ''; + + function throwSyntaxError( current, i, partial ) { + + var error = new SyntaxError( 'Unexpected character "' + current + '" at index ' + i + '.' ); + error.partial = partial; + throw error; + + } + + function newNumber() { + + if ( number !== '' ) { + + if ( exponent === '' ) result.push( Number( number ) ); + else result.push( Number( number ) * Math.pow( 10, Number( exponent ) ) ); + + } + + number = ''; + exponent = ''; + + } + + var current, i = 0, length = input.length; + for ( i = 0; i < length; i ++ ) { + + current = input[ i ]; + + // parse until next number + if ( state === SEP ) { + + // eat whitespace + if ( RE.WHITESPACE.test( current ) ) { + + continue; + + } + + // start new number + if ( RE.DIGIT.test( current ) || RE.SIGN.test( current ) ) { + + state = INT; + number = current; + continue; + + } + + if ( RE.POINT.test( current ) ) { + + state = FLOAT; + number = current; + continue; + + } + + // throw on double commas (e.g. "1, , 2") + if ( RE.COMMA.test( current ) ) { + + if ( seenComma ) { + + throwSyntaxError( current, i, result ); + + } + + seenComma = true; + + } + + } + + // parse integer part + if ( state === INT ) { + + if ( RE.DIGIT.test( current ) ) { + + number += current; + continue; + + } + + if ( RE.POINT.test( current ) ) { + + number += current; + state = FLOAT; + continue; + + } + + if ( RE.EXP.test( current ) ) { - if ( number.indexOf( '.' ) !== number.lastIndexOf( '.' ) ) { + state = EXP; + continue; - var split = number.split( '.' ); + } + + // throw on double signs ("-+1"), but not on sign as separator ("-1-2") + if ( RE.SIGN.test( current ) + && number.length === 1 + && RE.SIGN.test( number[ 0 ] ) ) { + + throwSyntaxError( current, i, result ); + + } + + } + + // parse decimal part + if ( state === FLOAT ) { + + if ( RE.DIGIT.test( current ) ) { + + number += current; + continue; + + } - for ( var s = 2; s < split.length; s ++ ) { + if ( RE.EXP.test( current ) ) { - array.splice( i + s - 1, 0, '0.' + split[ s ] ); + state = EXP; + continue; + + } + + // throw on double decimal points (e.g. "1..2") + if ( RE.POINT.test( current ) && number[ number.length - 1 ] === '.' ) { + + throwSyntaxError( current, i, result ); } } - array[ i ] = parseFloatWithUnits( number ); + // parse exponent part + if ( state == EXP ) { + + if ( RE.DIGIT.test( current ) ) { + + exponent += current; + continue; + + } + + if ( RE.SIGN.test( current ) ) { + + if ( exponent === '' ) { + + exponent += current; + continue; + + } + + if ( exponent.length === 1 && RE.SIGN.test( exponent ) ) { + + throwSyntaxError( current, i, result ); + + } + + } + + } + + + // end of number + if ( RE.WHITESPACE.test( current ) ) { + + newNumber(); + state = SEP; + seenComma = false; + + } else if ( RE.COMMA.test( current ) ) { + + newNumber(); + state = SEP; + seenComma = true; + + } else if ( RE.SIGN.test( current ) ) { + + newNumber(); + state = INT; + number = current; + + } else if ( RE.POINT.test( current ) ) { + + newNumber(); + state = FLOAT; + number = current; + + } else { + + throwSyntaxError( current, i, result ); + + } } - return array; + // add the last number found (if any) + newNumber(); + return result; }