forked from enviPath/enviPy
Current Dev State
This commit is contained in:
151
static/js/ketcher2/node_modules/svg-pathdata/src/SVGPathData.js
generated
vendored
Executable file
151
static/js/ketcher2/node_modules/svg-pathdata/src/SVGPathData.js
generated
vendored
Executable file
@ -0,0 +1,151 @@
|
||||
'use strict';
|
||||
|
||||
function SVGPathData(content) {
|
||||
this.commands = SVGPathData.parse(content);
|
||||
}
|
||||
|
||||
SVGPathData.prototype.encode = function() {
|
||||
return SVGPathData.encode(this.commands);
|
||||
};
|
||||
|
||||
SVGPathData.prototype.round = function() {
|
||||
return this.transform.apply(this, [SVGPathData.Transformer.ROUND].concat(
|
||||
[].slice.call(arguments, 0)));
|
||||
};
|
||||
|
||||
SVGPathData.prototype.toAbs = function() {
|
||||
return this.transform(SVGPathData.Transformer.TO_ABS);
|
||||
};
|
||||
|
||||
SVGPathData.prototype.toRel = function() {
|
||||
return this.transform(SVGPathData.Transformer.TO_REL);
|
||||
};
|
||||
|
||||
SVGPathData.prototype.translate = function() {
|
||||
return this.transform.apply(this, [SVGPathData.Transformer.TRANSLATE].concat(
|
||||
[].slice.call(arguments, 0)));
|
||||
};
|
||||
|
||||
SVGPathData.prototype.scale = function() {
|
||||
return this.transform.apply(this, [SVGPathData.Transformer.SCALE].concat(
|
||||
[].slice.call(arguments, 0)));
|
||||
};
|
||||
|
||||
SVGPathData.prototype.rotate = function() {
|
||||
return this.transform.apply(this, [SVGPathData.Transformer.ROTATE].concat(
|
||||
[].slice.call(arguments, 0)));
|
||||
};
|
||||
|
||||
SVGPathData.prototype.matrix = function() {
|
||||
return this.transform.apply(this, [SVGPathData.Transformer.MATRIX].concat(
|
||||
[].slice.call(arguments, 0)));
|
||||
};
|
||||
|
||||
SVGPathData.prototype.skewX = function() {
|
||||
return this.transform.apply(this, [SVGPathData.Transformer.SKEW_X].concat(
|
||||
[].slice.call(arguments, 0)));
|
||||
};
|
||||
|
||||
SVGPathData.prototype.skewY = function() {
|
||||
return this.transform.apply(this, [SVGPathData.Transformer.SKEW_Y].concat(
|
||||
[].slice.call(arguments, 0)));
|
||||
};
|
||||
|
||||
SVGPathData.prototype.xSymetry = function() {
|
||||
return this.transform.apply(this, [SVGPathData.Transformer.X_AXIS_SIMETRY].concat(
|
||||
[].slice.call(arguments, 0)));
|
||||
};
|
||||
|
||||
SVGPathData.prototype.ySymetry = function() {
|
||||
return this.transform.apply(this, [SVGPathData.Transformer.Y_AXIS_SIMETRY].concat(
|
||||
[].slice.call(arguments, 0)));
|
||||
};
|
||||
|
||||
SVGPathData.prototype.aToC = function() {
|
||||
return this.transform.apply(this, [SVGPathData.Transformer.A_TO_C].concat(
|
||||
[].slice.call(arguments, 0)));
|
||||
};
|
||||
|
||||
SVGPathData.prototype.transform = function(transformFunction) {
|
||||
var newCommands = [];
|
||||
var curCommands = [];
|
||||
var commands = this.commands;
|
||||
var i;
|
||||
var ii;
|
||||
|
||||
transformFunction = transformFunction.apply(null, [].slice.call(arguments, 1));
|
||||
|
||||
for(i = 0, ii = commands.length; i < ii; i++) {
|
||||
curCommands = transformFunction(commands[i]);
|
||||
if(curCommands instanceof Array) {
|
||||
newCommands = newCommands.concat(curCommands);
|
||||
} else {
|
||||
newCommands.push(curCommands);
|
||||
}
|
||||
}
|
||||
this.commands = newCommands;
|
||||
return this;
|
||||
};
|
||||
|
||||
// Static methods
|
||||
SVGPathData.encode = function(commands) {
|
||||
var content = '';
|
||||
var encoder = new SVGPathData.Encoder();
|
||||
|
||||
encoder.on('readable', function() {
|
||||
var str;
|
||||
|
||||
do {
|
||||
str = encoder.read();
|
||||
if(null !== str) {
|
||||
content += str;
|
||||
}
|
||||
} while(null !== str);
|
||||
});
|
||||
encoder.write(commands);
|
||||
encoder.end();
|
||||
return content;
|
||||
};
|
||||
|
||||
SVGPathData.parse = function(content) {
|
||||
var commands = [];
|
||||
var parser = new SVGPathData.Parser();
|
||||
|
||||
parser.on('readable', function() {
|
||||
var command;
|
||||
|
||||
do {
|
||||
command = parser.read();
|
||||
if(null !== command) {
|
||||
commands.push(command);
|
||||
}
|
||||
} while(null !== command);
|
||||
});
|
||||
parser.write(content);
|
||||
parser.end();
|
||||
return commands;
|
||||
};
|
||||
|
||||
// Commands static vars
|
||||
SVGPathData.CLOSE_PATH = 1;
|
||||
SVGPathData.MOVE_TO = 2;
|
||||
SVGPathData.HORIZ_LINE_TO = 4;
|
||||
SVGPathData.VERT_LINE_TO = 8;
|
||||
SVGPathData.LINE_TO = 16;
|
||||
SVGPathData.CURVE_TO = 32;
|
||||
SVGPathData.SMOOTH_CURVE_TO = 64;
|
||||
SVGPathData.QUAD_TO = 128;
|
||||
SVGPathData.SMOOTH_QUAD_TO = 256;
|
||||
SVGPathData.ARC = 512;
|
||||
SVGPathData.DRAWING_COMMANDS =
|
||||
SVGPathData.HORIZ_LINE_TO | SVGPathData.VERT_LINE_TO | SVGPathData.LINE_TO |
|
||||
SVGPathData.CURVE_TO | SVGPathData.SMOOTH_CURVE_TO | SVGPathData.QUAD_TO |
|
||||
SVGPathData.SMOOTH_QUAD_TO | SVGPathData.ARC;
|
||||
|
||||
// Export the main contructor first (tests are failing otherwise)
|
||||
module.exports = SVGPathData;
|
||||
|
||||
// Expose the internal constructors
|
||||
SVGPathData.Parser = require('./SVGPathDataParser.js');
|
||||
SVGPathData.Encoder = require('./SVGPathDataEncoder.js');
|
||||
SVGPathData.Transformer = require('./SVGPathDataTransformer.js');
|
||||
106
static/js/ketcher2/node_modules/svg-pathdata/src/SVGPathDataEncoder.js
generated
vendored
Executable file
106
static/js/ketcher2/node_modules/svg-pathdata/src/SVGPathDataEncoder.js
generated
vendored
Executable file
@ -0,0 +1,106 @@
|
||||
'use strict';
|
||||
|
||||
// Encode SVG PathData
|
||||
// http://www.w3.org/TR/SVG/paths.html#PathDataBNF
|
||||
|
||||
// Access to SVGPathData constructor
|
||||
var SVGPathData = require('./SVGPathData.js');
|
||||
|
||||
// TransformStream inherance required modules
|
||||
var TransformStream = require('readable-stream').Transform;
|
||||
var util = require('util');
|
||||
|
||||
// Private consts : Char groups
|
||||
var WSP = ' ';
|
||||
|
||||
// Inherit of writeable stream
|
||||
util.inherits(SVGPathDataEncoder, TransformStream);
|
||||
|
||||
// Constructor
|
||||
function SVGPathDataEncoder(options) {
|
||||
|
||||
// Ensure new were used
|
||||
if(!(this instanceof SVGPathDataEncoder)) {
|
||||
return new SVGPathDataEncoder(options);
|
||||
}
|
||||
|
||||
// Parent constructor
|
||||
TransformStream.call(this, {
|
||||
objectMode: true,
|
||||
});
|
||||
|
||||
// Setting objectMode separately
|
||||
this._writableState.objectMode = true;
|
||||
this._readableState.objectMode = false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Read method
|
||||
SVGPathDataEncoder.prototype._transform = function(commands, encoding, done) {
|
||||
var str = '';
|
||||
var i;
|
||||
var j;
|
||||
|
||||
if(!(commands instanceof Array)) {
|
||||
commands = [commands];
|
||||
}
|
||||
for(i = 0, j = commands.length; i < j; i++) {
|
||||
// Horizontal move to command
|
||||
if(commands[i].type === SVGPathData.CLOSE_PATH) {
|
||||
str += 'z';
|
||||
continue;
|
||||
// Horizontal move to command
|
||||
} else if(commands[i].type === SVGPathData.HORIZ_LINE_TO) {
|
||||
str += (commands[i].relative ? 'h' : 'H') +
|
||||
commands[i].x;
|
||||
// Vertical move to command
|
||||
} else if(commands[i].type === SVGPathData.VERT_LINE_TO) {
|
||||
str += (commands[i].relative ? 'v' : 'V') +
|
||||
commands[i].y;
|
||||
// Move to command
|
||||
} else if(commands[i].type === SVGPathData.MOVE_TO) {
|
||||
str += (commands[i].relative ? 'm' : 'M') +
|
||||
commands[i].x + WSP + commands[i].y;
|
||||
// Line to command
|
||||
} else if(commands[i].type === SVGPathData.LINE_TO) {
|
||||
str += (commands[i].relative ? 'l' : 'L') +
|
||||
commands[i].x + WSP + commands[i].y;
|
||||
// Curve to command
|
||||
} else if(commands[i].type === SVGPathData.CURVE_TO) {
|
||||
str += (commands[i].relative ? 'c' : 'C') +
|
||||
commands[i].x2 + WSP + commands[i].y2 +
|
||||
WSP + commands[i].x1 + WSP + commands[i].y1 +
|
||||
WSP + commands[i].x + WSP + commands[i].y;
|
||||
// Smooth curve to command
|
||||
} else if(commands[i].type === SVGPathData.SMOOTH_CURVE_TO) {
|
||||
str += (commands[i].relative ? 's' : 'S') +
|
||||
commands[i].x2 + WSP + commands[i].y2 +
|
||||
WSP + commands[i].x + WSP + commands[i].y;
|
||||
// Quadratic bezier curve to command
|
||||
} else if(commands[i].type === SVGPathData.QUAD_TO) {
|
||||
str += (commands[i].relative ? 'q' : 'Q') +
|
||||
commands[i].x1 + WSP + commands[i].y1 +
|
||||
WSP + commands[i].x + WSP + commands[i].y;
|
||||
// Smooth quadratic bezier curve to command
|
||||
} else if(commands[i].type === SVGPathData.SMOOTH_QUAD_TO) {
|
||||
str += (commands[i].relative ? 't' : 'T') +
|
||||
commands[i].x + WSP + commands[i].y;
|
||||
// Elliptic arc command
|
||||
} else if(commands[i].type === SVGPathData.ARC) {
|
||||
str += (commands[i].relative ? 'a' : 'A') +
|
||||
commands[i].rX + WSP + commands[i].rY +
|
||||
WSP + commands[i].xRot +
|
||||
WSP + commands[i].lArcFlag + WSP + commands[i].sweepFlag +
|
||||
WSP + commands[i].x + WSP + commands[i].y;
|
||||
// Unkown command
|
||||
} else {
|
||||
this.emit('error', new Error('Unexpected command type "' +
|
||||
commands[i].type + '" at index ' + i + '.'));
|
||||
}
|
||||
}
|
||||
this.push(new Buffer(str, 'utf8'));
|
||||
done();
|
||||
};
|
||||
|
||||
module.exports = SVGPathDataEncoder;
|
||||
508
static/js/ketcher2/node_modules/svg-pathdata/src/SVGPathDataParser.js
generated
vendored
Executable file
508
static/js/ketcher2/node_modules/svg-pathdata/src/SVGPathDataParser.js
generated
vendored
Executable file
@ -0,0 +1,508 @@
|
||||
'use strict';
|
||||
|
||||
// Parse SVG PathData
|
||||
// http://www.w3.org/TR/SVG/paths.html#PathDataBNF
|
||||
|
||||
// Access to SVGPathData constructor
|
||||
var SVGPathData = require('./SVGPathData.js');
|
||||
|
||||
// TransformStream inherance required modules
|
||||
var TransformStream = require('readable-stream').Transform;
|
||||
var util = require('util');
|
||||
|
||||
// Private consts : Char groups
|
||||
var WSP = [' ', '\t', '\r', '\n'];
|
||||
var DIGITS = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
||||
var SIGNS = ['-', '+'];
|
||||
var EXPONENTS = ['e', 'E'];
|
||||
var DECPOINT = ['.'];
|
||||
var FLAGS = ['0', '1'];
|
||||
var COMMA = [','];
|
||||
var COMMANDS = [
|
||||
'm', 'M', 'z', 'Z', 'l', 'L', 'h', 'H', 'v', 'V', 'c', 'C',
|
||||
's', 'S', 'q', 'Q', 't', 'T', 'a', 'A',
|
||||
];
|
||||
|
||||
// Inherit of transform stream
|
||||
util.inherits(SVGPathDataParser, TransformStream);
|
||||
|
||||
// Constructor
|
||||
function SVGPathDataParser(options) {
|
||||
|
||||
// Ensure new were used
|
||||
if(!(this instanceof SVGPathDataParser)) {
|
||||
return new SVGPathDataParser(options);
|
||||
}
|
||||
|
||||
// Parent constructor
|
||||
TransformStream.call(this, {
|
||||
objectMode: true,
|
||||
});
|
||||
|
||||
// Setting objectMode separately
|
||||
this._writableState.objectMode = false;
|
||||
this._readableState.objectMode = true;
|
||||
|
||||
// Parsing vars
|
||||
this.state = SVGPathDataParser.STATE_COMMAS_WSPS;
|
||||
this.curNumber = '';
|
||||
this.curCommand = null;
|
||||
this._flush = function(callback) {
|
||||
this._transform(new Buffer(' '), 'utf-8', function() {});
|
||||
// Adding residual command
|
||||
if(null !== this.curCommand) {
|
||||
if(this.curCommand.invalid) {
|
||||
this.emit('error',
|
||||
new SyntaxError('Unterminated command at the path end.'));
|
||||
}
|
||||
this.push(this.curCommand);
|
||||
this.curCommand = null;
|
||||
this.state ^= this.state & SVGPathDataParser.STATE_COMMANDS_MASK;
|
||||
}
|
||||
callback();
|
||||
};
|
||||
this._transform = function(chunk, encoding, callback) {
|
||||
var str = chunk.toString('buffer' !== encoding ? encoding : 'utf8');
|
||||
var i;
|
||||
var j;
|
||||
|
||||
for(i = 0, j = str.length; i < j; i++) {
|
||||
// White spaces parsing
|
||||
if(this.state & SVGPathDataParser.STATE_WSP ||
|
||||
this.state & SVGPathDataParser.STATE_WSPS) {
|
||||
if(-1 !== WSP.indexOf(str[i])) {
|
||||
this.state ^= this.state & SVGPathDataParser.STATE_WSP;
|
||||
// any space stops current number parsing
|
||||
if('' !== this.curNumber) {
|
||||
this.state ^= this.state & SVGPathDataParser.STATE_NUMBER_MASK;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Commas parsing
|
||||
if(this.state & SVGPathDataParser.STATE_COMMA ||
|
||||
this.state & SVGPathDataParser.STATE_COMMAS) {
|
||||
if(-1 !== COMMA.indexOf(str[i])) {
|
||||
this.state ^= this.state & SVGPathDataParser.STATE_COMMA;
|
||||
// any comma stops current number parsing
|
||||
if('' !== this.curNumber) {
|
||||
this.state ^= this.state & SVGPathDataParser.STATE_NUMBER_MASK;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Numbers parsing : -125.25e-125
|
||||
if(this.state & SVGPathDataParser.STATE_NUMBER) {
|
||||
// Reading the sign
|
||||
if((this.state & SVGPathDataParser.STATE_NUMBER_MASK) ===
|
||||
SVGPathDataParser.STATE_NUMBER) {
|
||||
this.state |= SVGPathDataParser.STATE_NUMBER_INT |
|
||||
SVGPathDataParser.STATE_NUMBER_DIGITS;
|
||||
if(-1 !== SIGNS.indexOf(str[i])) {
|
||||
this.curNumber += str[i];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Reading the exponent sign
|
||||
if(this.state & SVGPathDataParser.STATE_NUMBER_EXPSIGN) {
|
||||
this.state ^= SVGPathDataParser.STATE_NUMBER_EXPSIGN;
|
||||
this.state |= SVGPathDataParser.STATE_NUMBER_DIGITS;
|
||||
if(-1 !== SIGNS.indexOf(str[i])) {
|
||||
this.curNumber += str[i];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Reading digits
|
||||
if(this.state & SVGPathDataParser.STATE_NUMBER_DIGITS) {
|
||||
if(-1 !== DIGITS.indexOf(str[i])) {
|
||||
this.curNumber += str[i];
|
||||
continue;
|
||||
}
|
||||
this.state ^= SVGPathDataParser.STATE_NUMBER_DIGITS;
|
||||
}
|
||||
// Ended reading left side digits
|
||||
if(this.state & SVGPathDataParser.STATE_NUMBER_INT) {
|
||||
this.state ^= SVGPathDataParser.STATE_NUMBER_INT;
|
||||
// if got a point, reading right side digits
|
||||
if(-1 !== DECPOINT.indexOf(str[i])) {
|
||||
this.curNumber += str[i];
|
||||
this.state |= SVGPathDataParser.STATE_NUMBER_FLOAT |
|
||||
SVGPathDataParser.STATE_NUMBER_DIGITS;
|
||||
continue;
|
||||
// if got e/E, reading the exponent
|
||||
} else if(-1 !== EXPONENTS.indexOf(str[i])) {
|
||||
this.curNumber += str[i];
|
||||
this.state |= SVGPathDataParser.STATE_NUMBER_EXP |
|
||||
SVGPathDataParser.STATE_NUMBER_EXPSIGN;
|
||||
continue;
|
||||
}
|
||||
// else we're done with that number
|
||||
this.state ^= this.state & SVGPathDataParser.STATE_NUMBER_MASK;
|
||||
}
|
||||
// Ended reading decimal digits
|
||||
if(this.state & SVGPathDataParser.STATE_NUMBER_FLOAT) {
|
||||
this.state ^= SVGPathDataParser.STATE_NUMBER_FLOAT;
|
||||
// if got e/E, reading the exponent
|
||||
if(-1 !== EXPONENTS.indexOf(str[i])) {
|
||||
this.curNumber += str[i];
|
||||
this.state |= SVGPathDataParser.STATE_NUMBER_EXP |
|
||||
SVGPathDataParser.STATE_NUMBER_EXPSIGN;
|
||||
continue;
|
||||
}
|
||||
// else we're done with that number
|
||||
this.state ^= this.state & SVGPathDataParser.STATE_NUMBER_MASK;
|
||||
}
|
||||
// Ended reading exponent digits
|
||||
if(this.state & SVGPathDataParser.STATE_NUMBER_EXP) {
|
||||
// we're done with that number
|
||||
this.state ^= this.state & SVGPathDataParser.STATE_NUMBER_MASK;
|
||||
}
|
||||
}
|
||||
// New number
|
||||
if(this.curNumber) {
|
||||
// Horizontal move to command (x)
|
||||
if(this.state & SVGPathDataParser.STATE_HORIZ_LINE_TO) {
|
||||
if(null === this.curCommand) {
|
||||
this.push({
|
||||
type: SVGPathData.HORIZ_LINE_TO,
|
||||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE),
|
||||
x: Number(this.curNumber),
|
||||
});
|
||||
} else {
|
||||
this.curCommand.x = Number(this.curNumber);
|
||||
delete this.curCommand.invalid;
|
||||
this.push(this.curCommand);
|
||||
this.curCommand = null;
|
||||
}
|
||||
this.state |= SVGPathDataParser.STATE_NUMBER;
|
||||
// Vertical move to command (y)
|
||||
} else if(this.state & SVGPathDataParser.STATE_VERT_LINE_TO) {
|
||||
if(null === this.curCommand) {
|
||||
this.push({
|
||||
type: SVGPathData.VERT_LINE_TO,
|
||||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE),
|
||||
y: Number(this.curNumber),
|
||||
});
|
||||
} else {
|
||||
this.curCommand.y = Number(this.curNumber);
|
||||
delete this.curCommand.invalid;
|
||||
this.push(this.curCommand);
|
||||
this.curCommand = null;
|
||||
}
|
||||
this.state |= SVGPathDataParser.STATE_NUMBER;
|
||||
// Move to / line to / smooth quadratic curve to commands (x, y)
|
||||
} else if(this.state & SVGPathDataParser.STATE_MOVE_TO ||
|
||||
this.state & SVGPathDataParser.STATE_LINE_TO ||
|
||||
this.state & SVGPathDataParser.STATE_SMOOTH_QUAD_TO) {
|
||||
if(null === this.curCommand) {
|
||||
this.curCommand = {
|
||||
type: (this.state & SVGPathDataParser.STATE_MOVE_TO ?
|
||||
SVGPathData.MOVE_TO :
|
||||
(this.state & SVGPathDataParser.STATE_LINE_TO ?
|
||||
SVGPathData.LINE_TO : SVGPathData.SMOOTH_QUAD_TO
|
||||
)
|
||||
),
|
||||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE),
|
||||
x: Number(this.curNumber),
|
||||
};
|
||||
} else if('undefined' === typeof this.curCommand.x) {
|
||||
this.curCommand.x = Number(this.curNumber);
|
||||
} else {
|
||||
delete this.curCommand.invalid;
|
||||
this.curCommand.y = Number(this.curNumber);
|
||||
this.push(this.curCommand);
|
||||
this.curCommand = null;
|
||||
// Switch to line to state
|
||||
if(this.state & SVGPathDataParser.STATE_MOVE_TO) {
|
||||
this.state ^= SVGPathDataParser.STATE_MOVE_TO;
|
||||
this.state |= SVGPathDataParser.STATE_LINE_TO;
|
||||
}
|
||||
}
|
||||
this.state |= SVGPathDataParser.STATE_NUMBER;
|
||||
// Curve to commands (x1, y1, x2, y2, x, y)
|
||||
} else if(this.state & SVGPathDataParser.STATE_CURVE_TO) {
|
||||
if(null === this.curCommand) {
|
||||
this.curCommand = {
|
||||
type: SVGPathData.CURVE_TO,
|
||||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE),
|
||||
invalid: true,
|
||||
x2: Number(this.curNumber),
|
||||
};
|
||||
} else if('undefined' === typeof this.curCommand.x2) {
|
||||
this.curCommand.x2 = Number(this.curNumber);
|
||||
} else if('undefined' === typeof this.curCommand.y2) {
|
||||
this.curCommand.y2 = Number(this.curNumber);
|
||||
} else if('undefined' === typeof this.curCommand.x1) {
|
||||
this.curCommand.x1 = Number(this.curNumber);
|
||||
} else if('undefined' === typeof this.curCommand.y1) {
|
||||
this.curCommand.y1 = Number(this.curNumber);
|
||||
} else if('undefined' === typeof this.curCommand.x) {
|
||||
this.curCommand.x = Number(this.curNumber);
|
||||
} else if('undefined' === typeof this.curCommand.y) {
|
||||
this.curCommand.y = Number(this.curNumber);
|
||||
delete this.curCommand.invalid;
|
||||
this.push(this.curCommand);
|
||||
this.curCommand = null;
|
||||
}
|
||||
this.state |= SVGPathDataParser.STATE_NUMBER;
|
||||
// Smooth curve to commands (x1, y1, x, y)
|
||||
} else if(this.state & SVGPathDataParser.STATE_SMOOTH_CURVE_TO) {
|
||||
if(null === this.curCommand) {
|
||||
this.curCommand = {
|
||||
type: SVGPathData.SMOOTH_CURVE_TO,
|
||||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE),
|
||||
invalid: true,
|
||||
x2: Number(this.curNumber),
|
||||
};
|
||||
} else if('undefined' === typeof this.curCommand.x2) {
|
||||
this.curCommand.x2 = Number(this.curNumber);
|
||||
} else if('undefined' === typeof this.curCommand.y2) {
|
||||
this.curCommand.y2 = Number(this.curNumber);
|
||||
} else if('undefined' === typeof this.curCommand.x) {
|
||||
this.curCommand.x = Number(this.curNumber);
|
||||
} else if('undefined' === typeof this.curCommand.y) {
|
||||
this.curCommand.y = Number(this.curNumber);
|
||||
delete this.curCommand.invalid;
|
||||
this.push(this.curCommand);
|
||||
this.curCommand = null;
|
||||
}
|
||||
this.state |= SVGPathDataParser.STATE_NUMBER;
|
||||
// Quadratic bezier curve to commands (x1, y1, x, y)
|
||||
} else if(this.state & SVGPathDataParser.STATE_QUAD_TO) {
|
||||
if(null === this.curCommand) {
|
||||
this.curCommand = {
|
||||
type: SVGPathData.QUAD_TO,
|
||||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE),
|
||||
invalid: true,
|
||||
x1: Number(this.curNumber),
|
||||
};
|
||||
} else if('undefined' === typeof this.curCommand.x1) {
|
||||
this.curCommand.x1 = Number(this.curNumber);
|
||||
} else if('undefined' === typeof this.curCommand.y1) {
|
||||
this.curCommand.y1 = Number(this.curNumber);
|
||||
} else if('undefined' === typeof this.curCommand.x) {
|
||||
this.curCommand.x = Number(this.curNumber);
|
||||
} else if('undefined' === typeof this.curCommand.y) {
|
||||
this.curCommand.y = Number(this.curNumber);
|
||||
delete this.curCommand.invalid;
|
||||
this.push(this.curCommand);
|
||||
this.curCommand = null;
|
||||
}
|
||||
this.state |= SVGPathDataParser.STATE_NUMBER;
|
||||
// Elliptic arc commands (rX, rY, xRot, lArcFlag, sweepFlag, x, y)
|
||||
} else if(this.state & SVGPathDataParser.STATE_ARC) {
|
||||
if(null === this.curCommand) {
|
||||
this.curCommand = {
|
||||
type: SVGPathData.ARC,
|
||||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE),
|
||||
invalid: true,
|
||||
rX: Number(this.curNumber),
|
||||
};
|
||||
} else if('undefined' === typeof this.curCommand.rX) {
|
||||
if(0 > Number(this.curNumber)) {
|
||||
this.emit('error', new SyntaxError('Expected positive number,' +
|
||||
' got "' + this.curNumber + '" at index "' + i + '"'));
|
||||
}
|
||||
this.curCommand.rX = Number(this.curNumber);
|
||||
} else if('undefined' === typeof this.curCommand.rY) {
|
||||
if(0 > Number(this.curNumber)) {
|
||||
this.emit('error', new SyntaxError('Expected positive number,' +
|
||||
' got "' + this.curNumber + '" at index "' + i + '"'));
|
||||
}
|
||||
this.curCommand.rY = Number(this.curNumber);
|
||||
} else if('undefined' === typeof this.curCommand.xRot) {
|
||||
this.curCommand.xRot = Number(this.curNumber);
|
||||
} else if('undefined' === typeof this.curCommand.lArcFlag) {
|
||||
if(-1 === FLAGS.indexOf(this.curNumber)) {
|
||||
this.emit('error', new SyntaxError('Expected a flag, got "' +
|
||||
this.curNumber + '" at index "' + i + '"'));
|
||||
}
|
||||
this.curCommand.lArcFlag = Number(this.curNumber);
|
||||
} else if('undefined' === typeof this.curCommand.sweepFlag) {
|
||||
if('0' !== this.curNumber && '1' !== this.curNumber) {
|
||||
this.emit('error', new SyntaxError('Expected a flag, got "' +
|
||||
this.curNumber + '" at index "' + i + '"'));
|
||||
}
|
||||
this.curCommand.sweepFlag = Number(this.curNumber);
|
||||
} else if('undefined' === typeof this.curCommand.x) {
|
||||
this.curCommand.x = Number(this.curNumber);
|
||||
} else if('undefined' === typeof this.curCommand.y) {
|
||||
this.curCommand.y = Number(this.curNumber);
|
||||
delete this.curCommand.invalid;
|
||||
this.push(this.curCommand);
|
||||
this.curCommand = null;
|
||||
}
|
||||
this.state |= SVGPathDataParser.STATE_NUMBER;
|
||||
}
|
||||
this.curNumber = '';
|
||||
// Continue if a white space or a comma was detected
|
||||
if(-1 !== WSP.indexOf(str[i]) || -1 !== COMMA.indexOf(str[i])) {
|
||||
continue;
|
||||
}
|
||||
// if a sign is detected, then parse the new number
|
||||
if(-1 !== SIGNS.indexOf(str[i])) {
|
||||
this.curNumber = str[i];
|
||||
this.state |= SVGPathDataParser.STATE_NUMBER_INT |
|
||||
SVGPathDataParser.STATE_NUMBER_DIGITS;
|
||||
continue;
|
||||
}
|
||||
// if the decpoint is detected, then parse the new number
|
||||
if(-1 !== DECPOINT.indexOf(str[i])) {
|
||||
this.curNumber = str[i];
|
||||
this.state |= SVGPathDataParser.STATE_NUMBER_FLOAT |
|
||||
SVGPathDataParser.STATE_NUMBER_DIGITS;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// End of a command
|
||||
if(-1 !== COMMANDS.indexOf(str[i])) {
|
||||
// Adding residual command
|
||||
if(null !== this.curCommand) {
|
||||
if(this.curCommand.invalid) {
|
||||
this.emit('error',
|
||||
new SyntaxError('Unterminated command at index ' + i + '.'));
|
||||
}
|
||||
this.push(this.curCommand);
|
||||
this.curCommand = null;
|
||||
this.state ^= this.state & SVGPathDataParser.STATE_COMMANDS_MASK;
|
||||
}
|
||||
}
|
||||
// Detecting the next command
|
||||
this.state ^= this.state & SVGPathDataParser.STATE_COMMANDS_MASK;
|
||||
// Is the command relative
|
||||
if(str[i] === str[i].toLowerCase()) {
|
||||
this.state |= SVGPathDataParser.STATE_RELATIVE;
|
||||
} else {
|
||||
this.state ^= this.state & SVGPathDataParser.STATE_RELATIVE;
|
||||
}
|
||||
// Horizontal move to command
|
||||
if('z' === str[i].toLowerCase()) {
|
||||
this.push({
|
||||
type: SVGPathData.CLOSE_PATH,
|
||||
});
|
||||
this.state = SVGPathDataParser.STATE_COMMAS_WSPS;
|
||||
continue;
|
||||
// Horizontal move to command
|
||||
} else if('h' === str[i].toLowerCase()) {
|
||||
this.state |= SVGPathDataParser.STATE_HORIZ_LINE_TO;
|
||||
this.curCommand = {
|
||||
type: SVGPathData.HORIZ_LINE_TO,
|
||||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE),
|
||||
invalid: true,
|
||||
};
|
||||
// Vertical move to command
|
||||
} else if('v' === str[i].toLowerCase()) {
|
||||
this.state |= SVGPathDataParser.STATE_VERT_LINE_TO;
|
||||
this.curCommand = {
|
||||
type: SVGPathData.VERT_LINE_TO,
|
||||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE),
|
||||
invalid: true,
|
||||
};
|
||||
// Move to command
|
||||
} else if('m' === str[i].toLowerCase()) {
|
||||
this.state |= SVGPathDataParser.STATE_MOVE_TO;
|
||||
this.curCommand = {
|
||||
type: SVGPathData.MOVE_TO,
|
||||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE),
|
||||
invalid: true,
|
||||
};
|
||||
// Line to command
|
||||
} else if('l' === str[i].toLowerCase()) {
|
||||
this.state |= SVGPathDataParser.STATE_LINE_TO;
|
||||
this.curCommand = {
|
||||
type: SVGPathData.LINE_TO,
|
||||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE),
|
||||
invalid: true,
|
||||
};
|
||||
// Curve to command
|
||||
} else if('c' === str[i].toLowerCase()) {
|
||||
this.state |= SVGPathDataParser.STATE_CURVE_TO;
|
||||
this.curCommand = {
|
||||
type: SVGPathData.CURVE_TO,
|
||||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE),
|
||||
invalid: true,
|
||||
};
|
||||
// Smooth curve to command
|
||||
} else if('s' === str[i].toLowerCase()) {
|
||||
this.state |= SVGPathDataParser.STATE_SMOOTH_CURVE_TO;
|
||||
this.curCommand = {
|
||||
type: SVGPathData.SMOOTH_CURVE_TO,
|
||||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE),
|
||||
invalid: true,
|
||||
};
|
||||
// Quadratic bezier curve to command
|
||||
} else if('q' === str[i].toLowerCase()) {
|
||||
this.state |= SVGPathDataParser.STATE_QUAD_TO;
|
||||
this.curCommand = {
|
||||
type: SVGPathData.QUAD_TO,
|
||||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE),
|
||||
invalid: true,
|
||||
};
|
||||
// Smooth quadratic bezier curve to command
|
||||
} else if('t' === str[i].toLowerCase()) {
|
||||
this.state |= SVGPathDataParser.STATE_SMOOTH_QUAD_TO;
|
||||
this.curCommand = {
|
||||
type: SVGPathData.SMOOTH_QUAD_TO,
|
||||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE),
|
||||
invalid: true,
|
||||
};
|
||||
// Elliptic arc command
|
||||
} else if('a' === str[i].toLowerCase()) {
|
||||
this.state |= SVGPathDataParser.STATE_ARC;
|
||||
this.curCommand = {
|
||||
type: SVGPathData.ARC,
|
||||
relative: !!(this.state & SVGPathDataParser.STATE_RELATIVE),
|
||||
invalid: true,
|
||||
};
|
||||
// Unkown command
|
||||
} else {
|
||||
this.emit('error', new SyntaxError('Unexpected character "' + str[i] +
|
||||
'" at index ' + i + '.'));
|
||||
}
|
||||
// White spaces can follow a command
|
||||
this.state |= SVGPathDataParser.STATE_COMMAS_WSPS |
|
||||
SVGPathDataParser.STATE_NUMBER;
|
||||
}
|
||||
callback();
|
||||
};
|
||||
}
|
||||
|
||||
// Static consts
|
||||
// Parsing states
|
||||
SVGPathDataParser.STATE_WSP = 1;
|
||||
SVGPathDataParser.STATE_WSPS = 2;
|
||||
SVGPathDataParser.STATE_COMMA = 4;
|
||||
SVGPathDataParser.STATE_COMMAS = 8;
|
||||
SVGPathDataParser.STATE_COMMAS_WSPS =
|
||||
SVGPathDataParser.STATE_WSP | SVGPathDataParser.STATE_WSPS |
|
||||
SVGPathDataParser.STATE_COMMA | SVGPathDataParser.STATE_COMMAS;
|
||||
SVGPathDataParser.STATE_NUMBER = 16;
|
||||
SVGPathDataParser.STATE_NUMBER_DIGITS = 32;
|
||||
SVGPathDataParser.STATE_NUMBER_INT = 64;
|
||||
SVGPathDataParser.STATE_NUMBER_FLOAT = 128;
|
||||
SVGPathDataParser.STATE_NUMBER_EXP = 256;
|
||||
SVGPathDataParser.STATE_NUMBER_EXPSIGN = 512;
|
||||
SVGPathDataParser.STATE_NUMBER_MASK = SVGPathDataParser.STATE_NUMBER |
|
||||
SVGPathDataParser.STATE_NUMBER_DIGITS | SVGPathDataParser.STATE_NUMBER_INT |
|
||||
SVGPathDataParser.STATE_NUMBER_EXP | SVGPathDataParser.STATE_NUMBER_FLOAT;
|
||||
SVGPathDataParser.STATE_RELATIVE = 1024;
|
||||
SVGPathDataParser.STATE_CLOSE_PATH = 2048; // Close path command (z/Z)
|
||||
SVGPathDataParser.STATE_MOVE_TO = 4096; // Move to command (m/M)
|
||||
SVGPathDataParser.STATE_LINE_TO = 8192; // Line to command (l/L=)
|
||||
SVGPathDataParser.STATE_HORIZ_LINE_TO = 16384; // Horizontal line to command (h/H)
|
||||
SVGPathDataParser.STATE_VERT_LINE_TO = 32768; // Vertical line to command (v/V)
|
||||
SVGPathDataParser.STATE_CURVE_TO = 65536; // Curve to command (c/C)
|
||||
SVGPathDataParser.STATE_SMOOTH_CURVE_TO = 131072; // Smooth curve to command (s/S)
|
||||
SVGPathDataParser.STATE_QUAD_TO = 262144; // Quadratic bezier curve to command (q/Q)
|
||||
SVGPathDataParser.STATE_SMOOTH_QUAD_TO = 524288; // Smooth quadratic bezier curve to command (t/T)
|
||||
SVGPathDataParser.STATE_ARC = 1048576; // Elliptic arc command (a/A)
|
||||
SVGPathDataParser.STATE_COMMANDS_MASK =
|
||||
SVGPathDataParser.STATE_CLOSE_PATH | SVGPathDataParser.STATE_MOVE_TO |
|
||||
SVGPathDataParser.STATE_LINE_TO | SVGPathDataParser.STATE_HORIZ_LINE_TO |
|
||||
SVGPathDataParser.STATE_VERT_LINE_TO | SVGPathDataParser.STATE_CURVE_TO |
|
||||
SVGPathDataParser.STATE_SMOOTH_CURVE_TO | SVGPathDataParser.STATE_QUAD_TO |
|
||||
SVGPathDataParser.STATE_SMOOTH_QUAD_TO | SVGPathDataParser.STATE_ARC;
|
||||
|
||||
module.exports = SVGPathDataParser;
|
||||
416
static/js/ketcher2/node_modules/svg-pathdata/src/SVGPathDataTransformer.js
generated
vendored
Executable file
416
static/js/ketcher2/node_modules/svg-pathdata/src/SVGPathDataTransformer.js
generated
vendored
Executable file
@ -0,0 +1,416 @@
|
||||
'use strict';
|
||||
|
||||
// Transform SVG PathData
|
||||
// http://www.w3.org/TR/SVG/paths.html#PathDataBNF
|
||||
|
||||
// a2c utility
|
||||
var a2c = require('./a2c.js');
|
||||
|
||||
// Access to SVGPathData constructor
|
||||
var SVGPathData = require('./SVGPathData.js');
|
||||
|
||||
// TransformStream inherance required modules
|
||||
var TransformStream = require('readable-stream').Transform;
|
||||
var util = require('util');
|
||||
|
||||
// Inherit of transform stream
|
||||
util.inherits(SVGPathDataTransformer, TransformStream);
|
||||
|
||||
function SVGPathDataTransformer(transformFunction) {
|
||||
// Ensure new were used
|
||||
if(!(this instanceof SVGPathDataTransformer)) {
|
||||
return new (SVGPathDataTransformer.bind.apply(SVGPathDataTransformer,
|
||||
[SVGPathDataTransformer].concat([].slice.call(arguments, 0))));
|
||||
}
|
||||
|
||||
// Transform function needed
|
||||
if('function' !== typeof transformFunction) {
|
||||
throw new Error('Please provide a transform callback to receive commands.');
|
||||
}
|
||||
this._transformer = transformFunction.apply(null, [].slice.call(arguments, 1));
|
||||
if('function' !== typeof this._transformer) {
|
||||
throw new Error('Please provide a valid transform (returning a function).');
|
||||
}
|
||||
|
||||
// Parent constructor
|
||||
TransformStream.call(this, {
|
||||
objectMode: true,
|
||||
});
|
||||
}
|
||||
|
||||
SVGPathDataTransformer.prototype._transform = function(commands, encoding, done) {
|
||||
var i;
|
||||
var j;
|
||||
|
||||
if(!(commands instanceof Array)) {
|
||||
commands = [commands];
|
||||
}
|
||||
for(i = 0, j = commands.length; i < j; i++) {
|
||||
this.push(this._transformer(commands[i]));
|
||||
}
|
||||
done();
|
||||
};
|
||||
|
||||
// Predefined transforming functions
|
||||
// Rounds commands values
|
||||
SVGPathDataTransformer.ROUND = function roundGenerator(roundVal) {
|
||||
roundVal = roundVal || 10e12;
|
||||
return function round(command) {
|
||||
// x1/y1 values
|
||||
if('undefined' !== typeof command.x1) {
|
||||
command.x1 = Math.round(command.x1 * roundVal) / roundVal;
|
||||
}
|
||||
if('undefined' !== typeof command.y1) {
|
||||
command.y1 = Math.round(command.y1 * roundVal) / roundVal;
|
||||
}
|
||||
// x2/y2 values
|
||||
if('undefined' !== typeof command.x2) {
|
||||
command.x2 = Math.round(command.x2 * roundVal) / roundVal;
|
||||
}
|
||||
if('undefined' !== typeof command.y2) {
|
||||
command.y2 = Math.round(command.y2 * roundVal) / roundVal;
|
||||
}
|
||||
// Finally x/y values
|
||||
if('undefined' !== typeof command.x) {
|
||||
command.x = Math.round(command.x * roundVal, 12) / roundVal;
|
||||
}
|
||||
if('undefined' !== typeof command.y) {
|
||||
command.y = Math.round(command.y * roundVal, 12) / roundVal;
|
||||
}
|
||||
return command;
|
||||
};
|
||||
};
|
||||
|
||||
// Relative to absolute commands
|
||||
SVGPathDataTransformer.TO_ABS = function toAbsGenerator() {
|
||||
var prevX = 0;
|
||||
var prevY = 0;
|
||||
var pathStartX = NaN;
|
||||
var pathStartY = NaN;
|
||||
|
||||
return function toAbs(command) {
|
||||
if(isNaN(pathStartX) && (command.type & SVGPathData.DRAWING_COMMANDS)) {
|
||||
pathStartX = prevX;
|
||||
pathStartY = prevY;
|
||||
}
|
||||
if((command.type & SVGPathData.CLOSE_PATH) && !isNaN(pathStartX)) {
|
||||
prevX = isNaN(pathStartX) ? 0 : pathStartX;
|
||||
prevY = isNaN(pathStartY) ? 0 : pathStartY;
|
||||
pathStartX = NaN;
|
||||
pathStartY = NaN;
|
||||
}
|
||||
if(command.relative) {
|
||||
// x1/y1 values
|
||||
if('undefined' !== typeof command.x1) {
|
||||
command.x1 = prevX + command.x1;
|
||||
}
|
||||
if('undefined' !== typeof command.y1) {
|
||||
command.y1 = prevY + command.y1;
|
||||
}
|
||||
// x2/y2 values
|
||||
if('undefined' !== typeof command.x2) {
|
||||
command.x2 = prevX + command.x2;
|
||||
}
|
||||
if('undefined' !== typeof command.y2) {
|
||||
command.y2 = prevY + command.y2;
|
||||
}
|
||||
// Finally x/y values
|
||||
if('undefined' !== typeof command.x) {
|
||||
command.x = prevX + command.x;
|
||||
}
|
||||
if('undefined' !== typeof command.y) {
|
||||
command.y = prevY + command.y;
|
||||
}
|
||||
command.relative = false;
|
||||
}
|
||||
prevX = ('undefined' !== typeof command.x ? command.x : prevX);
|
||||
prevY = ('undefined' !== typeof command.y ? command.y : prevY);
|
||||
if(command.type & SVGPathData.MOVE_TO) {
|
||||
pathStartX = prevX;
|
||||
pathStartY = prevY;
|
||||
}
|
||||
return command;
|
||||
};
|
||||
};
|
||||
|
||||
// Absolute to relative commands
|
||||
SVGPathDataTransformer.TO_REL = function toRelGenerator() {
|
||||
var prevX = 0;
|
||||
var prevY = 0;
|
||||
|
||||
return function toRel(command) {
|
||||
if(!command.relative) {
|
||||
// x1/y1 values
|
||||
if('undefined' !== typeof command.x1) {
|
||||
command.x1 -= prevX;
|
||||
}
|
||||
if('undefined' !== typeof command.y1) {
|
||||
command.y1 -= prevY;
|
||||
}
|
||||
// x2/y2 values
|
||||
if('undefined' !== typeof command.x2) {
|
||||
command.x2 -= prevX;
|
||||
}
|
||||
if('undefined' !== typeof command.y2) {
|
||||
command.y2 -= prevY;
|
||||
}
|
||||
// Finally x/y values
|
||||
if('undefined' !== typeof command.x) {
|
||||
command.x -= prevX;
|
||||
}
|
||||
if('undefined' !== typeof command.y) {
|
||||
command.y -= prevY;
|
||||
}
|
||||
command.relative = true;
|
||||
}
|
||||
prevX = ('undefined' !== typeof command.x ? prevX + command.x : prevX);
|
||||
prevY = ('undefined' !== typeof command.y ? prevY + command.y : prevY);
|
||||
return command;
|
||||
};
|
||||
};
|
||||
|
||||
// SVG Transforms : http://www.w3.org/TR/SVGTiny12/coords.html#TransformList
|
||||
// Matrix : http://apike.ca/prog_svg_transform.html
|
||||
SVGPathDataTransformer.MATRIX = function matrixGenerator(a, b, c, d, e, f) {
|
||||
var prevX;
|
||||
var prevY;
|
||||
|
||||
if('number' !== typeof a || 'number' !== typeof b ||
|
||||
'number' !== typeof c || 'number' !== typeof d ||
|
||||
'number' !== typeof e || 'number' !== typeof f) {
|
||||
throw new Error('A matrix transformation requires parameters' +
|
||||
' [a,b,c,d,e,f] to be set and to be numbers.');
|
||||
}
|
||||
return function matrix(command) {
|
||||
var origX = command.x;
|
||||
var origX1 = command.x1;
|
||||
var origX2 = command.x2;
|
||||
|
||||
if('undefined' !== typeof command.x) {
|
||||
command.x = (command.x * a) +
|
||||
('undefined' !== typeof command.y ?
|
||||
command.y : (command.relative ? 0 : prevY || 0)
|
||||
) * c +
|
||||
(command.relative && 'undefined' !== typeof prevX ? 0 : e);
|
||||
}
|
||||
if('undefined' !== typeof command.y) {
|
||||
command.y = ('undefined' !== typeof origX ?
|
||||
origX : (command.relative ? 0 : prevX || 0)
|
||||
) * b +
|
||||
command.y * d +
|
||||
(command.relative && 'undefined' !== typeof prevY ? 0 : f);
|
||||
}
|
||||
if('undefined' !== typeof command.x1) {
|
||||
command.x1 = command.x1 * a + command.y1 * c +
|
||||
(command.relative && 'undefined' !== typeof prevX ? 0 : e);
|
||||
}
|
||||
if('undefined' !== typeof command.y1) {
|
||||
command.y1 = origX1 * b + command.y1 * d +
|
||||
(command.relative && 'undefined' !== typeof prevY ? 0 : f);
|
||||
}
|
||||
if('undefined' !== typeof command.x2) {
|
||||
command.x2 = command.x2 * a + command.y2 * c +
|
||||
(command.relative && 'undefined' !== typeof prevX ? 0 : e);
|
||||
}
|
||||
if('undefined' !== typeof command.y2) {
|
||||
command.y2 = origX2 * b + command.y2 * d +
|
||||
(command.relative && 'undefined' !== typeof prevY ? 0 : f);
|
||||
}
|
||||
function sq(x) { return x*x; }
|
||||
var det = a*d - b*c;
|
||||
if('undefined' !== typeof command.xRot) {
|
||||
// Skip if this is a pure translation
|
||||
if(a !== 1 || b !== 0 || c !== 0 || d !== 1) {
|
||||
// Special case for singular matrix
|
||||
if(det === 0) {
|
||||
// In the singular case, the arc is compressed to a line. The actual geometric image of the original
|
||||
// curve under this transform possibly extends beyond the starting and/or ending points of the segment, but
|
||||
// for simplicity we ignore this detail and just replace this command with a single line segment.
|
||||
delete command.rX;
|
||||
delete command.rY;
|
||||
delete command.xRot;
|
||||
delete command.lArcFlag;
|
||||
delete command.sweepFlag;
|
||||
command.type = SVGPathData.LINE_TO;
|
||||
} else {
|
||||
// Convert to radians
|
||||
var xRot = command.xRot*Math.PI/180;
|
||||
|
||||
// Convert rotated ellipse to general conic form
|
||||
// x0^2/rX^2 + y0^2/rY^2 - 1 = 0
|
||||
// x0 = x*cos(xRot) + y*sin(xRot)
|
||||
// y0 = -x*sin(xRot) + y*cos(xRot)
|
||||
// --> A*x^2 + B*x*y + C*y^2 - 1 = 0, where
|
||||
var sinRot = Math.sin(xRot), cosRot = Math.cos(xRot),
|
||||
xCurve = 1/sq(command.rX), yCurve = 1/sq(command.rY);
|
||||
var A = sq(cosRot)*xCurve + sq(sinRot)*yCurve,
|
||||
B = 2*sinRot*cosRot*(xCurve - yCurve),
|
||||
C = sq(sinRot)*xCurve + sq(cosRot)*yCurve;
|
||||
|
||||
// Apply matrix to A*x^2 + B*x*y + C*y^2 - 1 = 0
|
||||
// x1 = a*x + c*y
|
||||
// y1 = b*x + d*y
|
||||
// (we can ignore e and f, since pure translations don't affect the shape of the ellipse)
|
||||
// --> A1*x1^2 + B1*x1*y1 + C1*y1^2 - det^2 = 0, where
|
||||
var A1 = A*d*d - B*b*d + C*b*b,
|
||||
B1 = B*(a*d + b*c) - 2*(A*c*d + C*a*b),
|
||||
C1 = A*c*c - B*a*c + C*a*a;
|
||||
|
||||
// Unapply newXRot to get back to axis-aligned ellipse equation
|
||||
// x1 = x2*cos(newXRot) - y2*sin(newXRot)
|
||||
// y1 = x2*sin(newXRot) + y2*cos(newXRot)
|
||||
// A1*x1^2 + B1*x1*y1 + C1*y1^2 - det^2 =
|
||||
// x2^2*(A1*cos(newXRot)^2 + B1*sin(newXRot)*cos(newXRot) + C1*sin(newXRot)^2)
|
||||
// + x2*y2*(2*(C1 - A1)*sin(newXRot)*cos(newXRot) + B1*(cos(newXRot)^2 - sin(newXRot)^2))
|
||||
// + y2^2*(A1*sin(newXRot)^2 - B1*sin(newXRot)*cos(newXRot) + C1*cos(newXRot)^2)
|
||||
// (which must have the same zeroes as)
|
||||
// x2^2/newRX^2 + y2^2/newRY^2 - 1
|
||||
// (so we have)
|
||||
// 2*(C1 - A1)*sin(newXRot)*cos(newXRot) + B1*(cos(newXRot)^2 - sin(newXRot)^2) = 0
|
||||
// (A1 - C1)*sin(2*newXRot) = B1*cos(2*newXRot)
|
||||
// 2*newXRot = atan2(B1, A1 - C1)
|
||||
var newXRot = ((Math.atan2(B1, A1 - C1) + Math.PI) % Math.PI)/2;
|
||||
// For any integer n, (atan2(B1, A1 - C1) + n*pi)/2 is a solution to the above; incrementing n just swaps the
|
||||
// x and y radii computed below (since that's what rotating an ellipse by pi/2 does). Choosing the rotation
|
||||
// between 0 and pi/2 eliminates the ambiguity and leads to more predictable output.
|
||||
|
||||
// Finally, we get newRX and newRY from the same-zeroes relationship that gave us newXRot
|
||||
var newSinRot = Math.sin(newXRot), newCosRot = Math.cos(newXRot);
|
||||
command.rX = Math.abs(det)/Math.sqrt(A1*sq(newCosRot) + B1*newSinRot*newCosRot + C1*sq(newSinRot));
|
||||
command.rY = Math.abs(det)/Math.sqrt(A1*sq(newSinRot) - B1*newSinRot*newCosRot + C1*sq(newCosRot));
|
||||
command.xRot = newXRot*180/Math.PI;
|
||||
}
|
||||
}
|
||||
}
|
||||
// sweepFlag needs to be inverted when mirroring shapes
|
||||
// see http://www.itk.ilstu.edu/faculty/javila/SVG/SVG_drawing1/elliptical_curve.htm
|
||||
// m 65,10 a 50,25 0 1 0 50,25
|
||||
// M 65,60 A 50,25 0 1 1 115,35
|
||||
if('undefined' !== typeof command.sweepFlag) {
|
||||
command.sweepFlag = (command.sweepFlag + (0 <= det ? 0 : 1)) % 2;
|
||||
}
|
||||
|
||||
prevX = ('undefined' !== typeof command.x ?
|
||||
(command.relative ? (prevX || 0) + command.x : command.x) :
|
||||
prevX || 0);
|
||||
prevY = ('undefined' !== typeof command.y ?
|
||||
(command.relative ? (prevY || 0) + command.y : command.y) :
|
||||
prevY || 0);
|
||||
return command;
|
||||
};
|
||||
};
|
||||
|
||||
// Rotation
|
||||
SVGPathDataTransformer.ROTATE = function rotateGenerator(a, x, y) {
|
||||
if('number' !== typeof a) {
|
||||
throw new Error('A rotate transformation requires the parameter a' +
|
||||
' to be set and to be a number.');
|
||||
}
|
||||
return (function(toOrigin, doRotate, fromOrigin) {
|
||||
return function rotate(command) {
|
||||
return fromOrigin(doRotate(toOrigin(command)));
|
||||
};
|
||||
})(SVGPathDataTransformer.TRANSLATE(-(x || 0), -(y || 0)),
|
||||
SVGPathDataTransformer.MATRIX(Math.cos(a), Math.sin(a),
|
||||
-Math.sin(a), Math.cos(a), 0, 0),
|
||||
SVGPathDataTransformer.TRANSLATE(x || 0, y || 0)
|
||||
);
|
||||
};
|
||||
|
||||
// Translation
|
||||
SVGPathDataTransformer.TRANSLATE = function translateGenerator(dX, dY) {
|
||||
if('number' !== typeof dX) {
|
||||
throw new Error('A translate transformation requires the parameter dX' +
|
||||
' to be set and to be a number.');
|
||||
}
|
||||
return SVGPathDataTransformer.MATRIX(1, 0, 0, 1, dX, dY || 0);
|
||||
};
|
||||
|
||||
// Scaling
|
||||
SVGPathDataTransformer.SCALE = function scaleGenerator(dX, dY) {
|
||||
if('number' !== typeof dX) {
|
||||
throw new Error('A scale transformation requires the parameter dX' +
|
||||
' to be set and to be a number.');
|
||||
}
|
||||
return SVGPathDataTransformer.MATRIX(dX, 0, 0, dY || dX, 0, 0);
|
||||
};
|
||||
|
||||
// Skew
|
||||
SVGPathDataTransformer.SKEW_X = function skewXGenerator(a) {
|
||||
if('number' !== typeof a) {
|
||||
throw new Error('A skewX transformation requires the parameter x' +
|
||||
' to be set and to be a number.');
|
||||
}
|
||||
return SVGPathDataTransformer.MATRIX(1, 0, Math.atan(a), 1, 0, 0);
|
||||
};
|
||||
SVGPathDataTransformer.SKEW_Y = function skewYGenerator(a) {
|
||||
if('number' !== typeof a) {
|
||||
throw new Error('A skewY transformation requires the parameter y' +
|
||||
' to be set and to be a number.');
|
||||
}
|
||||
return SVGPathDataTransformer.MATRIX(1, Math.atan(a), 0, 1, 0, 0);
|
||||
};
|
||||
|
||||
// Symetry througth the X axis
|
||||
SVGPathDataTransformer.X_AXIS_SIMETRY = function xSymetryGenerator(xDecal) {
|
||||
return (function(toAbs, scale, translate) {
|
||||
return function xSymetry(command) {
|
||||
return translate(scale(toAbs(command)));
|
||||
};
|
||||
})(SVGPathDataTransformer.TO_ABS(),
|
||||
SVGPathDataTransformer.SCALE(-1, 1),
|
||||
SVGPathDataTransformer.TRANSLATE(xDecal || 0, 0)
|
||||
);
|
||||
};
|
||||
|
||||
// Symetry througth the Y axis
|
||||
SVGPathDataTransformer.Y_AXIS_SIMETRY = function ySymetryGenerator(yDecal) {
|
||||
return (function(toAbs, scale, translate) {
|
||||
return function ySymetry(command) {
|
||||
return translate(scale(toAbs(command)));
|
||||
};
|
||||
})(SVGPathDataTransformer.TO_ABS(),
|
||||
SVGPathDataTransformer.SCALE(1, -1),
|
||||
SVGPathDataTransformer.TRANSLATE(0, yDecal || 0)
|
||||
);
|
||||
};
|
||||
|
||||
// Convert arc commands to curve commands
|
||||
SVGPathDataTransformer.A_TO_C = function a2CGenerator() {
|
||||
var prevX = 0;
|
||||
var prevY = 0;
|
||||
var args;
|
||||
|
||||
return (function(toAbs) {
|
||||
return function a2C(command) {
|
||||
var commands = [];
|
||||
var i;
|
||||
var ii;
|
||||
|
||||
command = toAbs(command);
|
||||
if(command.type === SVGPathData.ARC) {
|
||||
args = a2c(prevX, prevY, command.rX, command.rX, command.xRot,
|
||||
command.lArcFlag, command.sweepFlag, command.x, command.y);
|
||||
prevX = command.x; prevY = command.y;
|
||||
for(i = 0, ii = args.length; i < ii; i += 6) {
|
||||
commands.push({
|
||||
type: SVGPathData.CURVE_TO,
|
||||
relative: false,
|
||||
x2: args[i],
|
||||
y2: args[i + 1],
|
||||
x1: args[i + 2],
|
||||
y1: args[i + 3],
|
||||
x: args[i + 4],
|
||||
y: args[i + 5],
|
||||
});
|
||||
}
|
||||
return commands;
|
||||
}
|
||||
prevX = command.x; prevY = command.y;
|
||||
return command;
|
||||
|
||||
};
|
||||
})(SVGPathDataTransformer.TO_ABS());
|
||||
};
|
||||
|
||||
module.exports = SVGPathDataTransformer;
|
||||
127
static/js/ketcher2/node_modules/svg-pathdata/src/a2c.js
generated
vendored
Normal file
127
static/js/ketcher2/node_modules/svg-pathdata/src/a2c.js
generated
vendored
Normal file
@ -0,0 +1,127 @@
|
||||
// Borrowed from https://github.com/PPvG/svg-path/blob/master/lib/Path.js#L208
|
||||
// that were borrowed from https://github.com/DmitryBaranovskiy/raphael/blob/4d97d4ff5350bb949b88e6d78b877f76ea8b5e24/raphael.js#L2216-L2304
|
||||
// (MIT licensed; http://raphaeljs.com/license.html).
|
||||
|
||||
module.exports = a2c;
|
||||
|
||||
// LOL
|
||||
var PI = Math.PI;
|
||||
var math = Math;
|
||||
var abs = Math.abs;
|
||||
var split = "split";
|
||||
var concat = "concat";
|
||||
var apply = "apply";
|
||||
var has = "hasOwnProperty";
|
||||
|
||||
function a2c(x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) {
|
||||
// for more information of where this math came from visit:
|
||||
// http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
|
||||
var _120 = PI * 120 / 180,
|
||||
rad = PI / 180 * (+angle || 0),
|
||||
res = [],
|
||||
xy,
|
||||
rotate = cacher(function (x, y, rad) {
|
||||
var X = x * math.cos(rad) - y * math.sin(rad),
|
||||
Y = x * math.sin(rad) + y * math.cos(rad);
|
||||
return {x: X, y: Y};
|
||||
});
|
||||
if (!recursive) {
|
||||
xy = rotate(x1, y1, -rad);
|
||||
x1 = xy.x;
|
||||
y1 = xy.y;
|
||||
xy = rotate(x2, y2, -rad);
|
||||
x2 = xy.x;
|
||||
y2 = xy.y;
|
||||
var cos = math.cos(PI / 180 * angle),
|
||||
sin = math.sin(PI / 180 * angle),
|
||||
x = (x1 - x2) / 2,
|
||||
y = (y1 - y2) / 2;
|
||||
var h = (x * x) / (rx * rx) + (y * y) / (ry * ry);
|
||||
if (h > 1) {
|
||||
h = math.sqrt(h);
|
||||
rx = h * rx;
|
||||
ry = h * ry;
|
||||
}
|
||||
var rx2 = rx * rx,
|
||||
ry2 = ry * ry,
|
||||
k = (large_arc_flag == sweep_flag ? -1 : 1) *
|
||||
math.sqrt(abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))),
|
||||
cx = k * rx * y / ry + (x1 + x2) / 2,
|
||||
cy = k * -ry * x / rx + (y1 + y2) / 2,
|
||||
f1 = math.asin(((y1 - cy) / ry).toFixed(9)),
|
||||
f2 = math.asin(((y2 - cy) / ry).toFixed(9));
|
||||
|
||||
f1 = x1 < cx ? PI - f1 : f1;
|
||||
f2 = x2 < cx ? PI - f2 : f2;
|
||||
f1 < 0 && (f1 = PI * 2 + f1);
|
||||
f2 < 0 && (f2 = PI * 2 + f2);
|
||||
if (sweep_flag && f1 > f2) {
|
||||
f1 = f1 - PI * 2;
|
||||
}
|
||||
if (!sweep_flag && f2 > f1) {
|
||||
f2 = f2 - PI * 2;
|
||||
}
|
||||
} else {
|
||||
f1 = recursive[0];
|
||||
f2 = recursive[1];
|
||||
cx = recursive[2];
|
||||
cy = recursive[3];
|
||||
}
|
||||
var df = f2 - f1;
|
||||
if (abs(df) > _120) {
|
||||
var f2old = f2,
|
||||
x2old = x2,
|
||||
y2old = y2;
|
||||
f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1);
|
||||
x2 = cx + rx * math.cos(f2);
|
||||
y2 = cy + ry * math.sin(f2);
|
||||
res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]);
|
||||
}
|
||||
df = f2 - f1;
|
||||
var c1 = math.cos(f1),
|
||||
s1 = math.sin(f1),
|
||||
c2 = math.cos(f2),
|
||||
s2 = math.sin(f2),
|
||||
t = math.tan(df / 4),
|
||||
hx = 4 / 3 * rx * t,
|
||||
hy = 4 / 3 * ry * t,
|
||||
m1 = [x1, y1],
|
||||
m2 = [x1 + hx * s1, y1 - hy * c1],
|
||||
m3 = [x2 + hx * s2, y2 - hy * c2],
|
||||
m4 = [x2, y2];
|
||||
m2[0] = 2 * m1[0] - m2[0];
|
||||
m2[1] = 2 * m1[1] - m2[1];
|
||||
if (recursive) {
|
||||
return [m2, m3, m4][concat](res);
|
||||
} else {
|
||||
res = [m2, m3, m4][concat](res).join()[split](",");
|
||||
var newres = [];
|
||||
for (var i = 0, ii = res.length; i < ii; i++) {
|
||||
newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x;
|
||||
}
|
||||
return newres;
|
||||
}
|
||||
}
|
||||
function cacher(f, scope, postprocessor) {
|
||||
function newf() {
|
||||
var arg = Array.prototype.slice.call(arguments, 0),
|
||||
args = arg.join("\u2400"),
|
||||
cache = newf.cache = newf.cache || {},
|
||||
count = newf.count = newf.count || [];
|
||||
if (cache[has](args)) {
|
||||
repush(count, args);
|
||||
return postprocessor ? postprocessor(cache[args]) : cache[args];
|
||||
}
|
||||
count.length >= 1e3 && delete cache[count.shift()];
|
||||
count.push(args);
|
||||
cache[args] = f[apply](scope, arg);
|
||||
return postprocessor ? postprocessor(cache[args]) : cache[args];
|
||||
}
|
||||
return newf;
|
||||
}
|
||||
|
||||
function repush(array, item) {
|
||||
for (var i = 0, ii = array.length; i < ii; i++) if (array[i] === item) {
|
||||
return array.push(array.splice(i, 1)[0]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user