diff --git a/src/path/Path.Constructors.js b/src/path/Path.Constructors.js index 23616842..14d515c8 100644 --- a/src/path/Path.Constructors.js +++ b/src/path/Path.Constructors.js @@ -37,11 +37,12 @@ Path.inject({ statics: new function() { rect = Rectangle.read(arguments); var path = new Path(), corners = ['getBottomLeft', 'getTopLeft', 'getTopRight', - 'getBottomRight']; - for (var i = 0; i < 4; i++) { - path.add(rect[corners[i]]()); - } - path.setClosed(true); + 'getBottomRight'], + segments = new Array(4); + for (var i = 0; i < 4; i++) + segments[i] = new Segment(rect[corners[i]]()); + path._add(segments); + path._closed = true; return path; }, @@ -56,25 +57,24 @@ Path.inject({ statics: new function() { size = Size.min(size, rect.getSize().divide(2)); var path = new Path(), uSize = size.multiply(kappa * 2), - bl = rect.getBottomLeft(), tl = rect.getTopLeft(), tr = rect.getTopRight(), br = rect.getBottomRight(); + path._add([ + new Segment(bl.add(size.width, 0), null, [-uSize.width, 0]), + new Segment(bl.subtract(0, size.height), [0, uSize.height], null), - path.add(bl.add(size.width, 0), null, [-uSize.width, 0]); - path.add(bl.subtract(0, size.height), [0, uSize.height], null); + new Segment(tl.add(0, size.height), null, [0, -uSize.height]), + new Segment(tl.add(size.width, 0), [-uSize.width, 0], null), - path.add(tl.add(0, size.height), null, [0, -uSize.height]); - path.add(tl.add(size.width, 0), [-uSize.width, 0], null); + new Segment(tr.subtract(size.width, 0), null, [uSize.width, 0]), + new Segment(tr.add(0, size.height), [0, -uSize.height], null), - path.add(tr.subtract(size.width, 0), null, [uSize.width, 0]); - path.add(tr.add(0, size.height), [0, -uSize.height], null); - - path.add(br.subtract(0, size.height), null, [0, uSize.height]); - path.add(br.subtract(size.width, 0), [uSize.width, 0], null); - - path.setClosed(true); + new Segment(br.subtract(0, size.height), null, [0, uSize.height]), + new Segment(br.subtract(size.width, 0), [uSize.width, 0], null) + ]); + path._closed = true; return path; }, @@ -82,16 +82,18 @@ Path.inject({ statics: new function() { rect = Rectangle.read(arguments); var path = new Path(), topLeft = rect.getTopLeft(), - size = new Size(rect.width, rect.height); + size = new Size(rect.width, rect.height), + segments = new Array(4); for (var i = 0; i < 4; i++) { var segment = ovalSegments[i]; - path._add(new Segment( + segments[i] = new Segment( segment._point.multiply(size).add(topLeft), segment._handleIn.multiply(size), segment._handleOut.multiply(size) - )); + ); } - path.setClosed(true); + path._add(segments); + path._closed = true; return path; }, @@ -116,29 +118,33 @@ Path.inject({ statics: new function() { RegularPolygon: function(center, numSides, radius) { center = Point.read(arguments, 0, 1); var path = new Path(), + step = 360 / numSides, three = !(numSides % 3), vector = new Point(0, three ? -radius : radius), - offset = three ? -1 : 0.5; + offset = three ? -1 : 0.5, + segments = new Array(numSides); for (var i = 0; i < numSides; i++) { - var angle = (360 / numSides) * (i + offset); - path.add(center.add(vector.rotate(angle))); + segments[i] = new Segment(center.add( + vector.rotate((i + offset) * step))); } - path.setClosed(true); + path._add(segments); + path._closed = true; return path; }, Star: function(center, numPoints, radius1, radius2) { center = Point.read(arguments, 0, 1); numPoints *= 2; - var angle = 360 / numPoints, - path = new Path(); + var path = new Path(), + step = 360 / numPoints, + vector = new Point(0, -1), + segments = new Array(numPoints); for (var i = 0; i < numPoints; i++) { - path.add(center.add({ - angle: -90 + angle * i, - length: i % 2 ? radius2 : radius1 - })); + segments[i] = new Segment(center.add( + vector.rotate(step * i).multiply(i % 2 ? radius2 : radius1))); } - path.setClosed(true); + path._add(segments); + path._closed = true; return path; } }; diff --git a/src/path/Path.js b/src/path/Path.js index 0c48ed94..d12bb19b 100644 --- a/src/path/Path.js +++ b/src/path/Path.js @@ -52,8 +52,7 @@ var Path = this.Path = PathItem.extend({ if (this._curves) this._curves = null; } - for (var i = 0, l = segments.length; i < l; i++) - this._add(Segment.read(segments, i, 1)); + this._add(Segment.readAll(segments)); }, getFirstSegment: function() { @@ -137,60 +136,63 @@ var Path = this.Path = PathItem.extend({ * If a curves list was requested, it will kept in sync with the segments * list automatically. */ - // TODO: Add support for adding multiple segments at once - _add: function(segment, index) { + _add: function(segs, index) { // Local short-cuts: var segments = this._segments, - curves = this._curves; - // If this segment belongs to another path already, clone it before - // adding. - if (segment._path) - segment = new Segment(segment); - if (index === undefined) { - // Insert at the end - index = segments.push(segment) - 1; + curves = this._curves, + amount = segs.length, + append = index === undefined, + index = append ? segments.length : index; + for (var i = 0; i < amount; i++) { + var segment = segs[i]; + // If the segments belong to another path already, clone them before + // adding: + if (segment._path) + segment = segs[i] = new Segment(segment); + // Set _path and _index references for these new segments now + segment._path = this; + segment._index = index + i; + } + if (append) { + // Append them all at the end by using push + segments.push.apply(segments, segs); } else { // Insert somewhere else - segments.splice(index, 0, segment); + segments.splice.apply(segments, [index, 0].concat(segs)); // Adjust the indices of the segments above. - for (var i = index + 1, l = segments.length; i < l; i++) + for (var i = index + amount, l = segments.length; i < l; i++) segments[i]._index = i; } - segment._path = this; - segment._index = index; // Keep the curves list in sync all the time in case it as requested // already. We need to step one index down from the inserted segment to // get its curve: if (curves && --index >= 0) { // Insert a new curve as well and update the curves above curves.splice(index, 0, Curve.create(this, segments[index], - segments[++index])); + segments[index + 1])); // Adjust segment1 now for the curves above the inserted one - // (note the ++index in the statement above)/ - var curve = curves[index]; + var curve = curves[index + amount]; if (curve) - curve._segment1 = segments[index]; + curve._segment1 = segments[index + amount]; } this._changed(); - return segment; + return segs; }, - // TODO: Add support for adding multiple segments at once - add: function(segment) { - segment = Segment.read(arguments); - return segment ? this._add(segment) : null; + // TODO: Port back support for adding multiple segments at once to Sg + add: function(segment1 /*, segment2, ... */) { + return this._add(Segment.readAll(arguments)); }, - // TODO: Add support for adding multiple segments at once - insert: function(index, segment) { - segment = Segment.read(arguments, 1); - return segment ? this._add(segment, index) : null; + // TODO: Port back support for adding multiple segments at once to Sg + insert: function(index, segment1 /*, segment2, ... */) { + return this._add(Segment.readAll(arguments, 1), index); }, // TODO: Port back to Sg removeSegment: function(index) { var segments = this.removeSegments(index, index + 1); - return segments ? segments[0] : null; + return segments[0] || null; }, // TODO: Port back to Sg @@ -287,8 +289,7 @@ var Path = this.Path = PathItem.extend({ var first2 = path.getFirstSegment(); if (last1._point.equals(first2._point)) { last1.setHandleOut(first2._handleOut); - for (var i = 1, l = segments.length; i < l; i++) - this._add(segments[i]); + this._add(segments.slice(1)); } else { var first1 = this.getFirstSegment(); if (first1._point.equals(first2._point)) @@ -296,11 +297,10 @@ var Path = this.Path = PathItem.extend({ if (first1._point.equals(last2._point)) { first1.setHandleIn(last2._handleIn); // Prepend all segments from path except last one - for (var i = 0, l = segments.length - 1; i < l; i++) - this._add(segments[i], 0); + // TODO: Test if -1 (== all) or -2 (as described by comment) + this._add(segments.slice(0, segments.length - 2), 0); } else { - for (var i = 0, l = segments.length; i < l; i++) - this._add(segments[i]); + this._add(segments.slice(0)); } } path.remove(); @@ -679,12 +679,12 @@ var Path = this.Path = PathItem.extend({ // Let's not be picky about calling moveTo() when not at the // beginning of a path, just bail out: if (!this._segments.length) - this._add(new Segment(Point.read(arguments))); + this._add([new Segment(Point.read(arguments))]); }, lineTo: function() { // Let's not be picky about calling moveTo() first: - this._add(new Segment(Point.read(arguments))); + this._add([new Segment(Point.read(arguments))]); }, /** @@ -700,7 +700,7 @@ var Path = this.Path = PathItem.extend({ // Convert to relative values: current.setHandleOut(handle1.subtract(current._point)); // And add the new segment, with handleIn set to c2 - this._add(new Segment(to, handle2.subtract(to), new Point())); + this._add([new Segment(to, handle2.subtract(to), new Point())]); }, /** @@ -807,6 +807,7 @@ var Path = this.Path = PathItem.extend({ var halfInc = inc / 2, z = 4 / 3 * Math.sin(halfInc) / (1 + Math.cos(halfInc)); + var segments = []; for (var i = 0; i <= arcSegs; i++) { var relx = Math.cos(angle), rely = Math.sin(angle), @@ -829,10 +830,12 @@ var Path = this.Path = PathItem.extend({ var handleIn = new Point( centerX + (relx + z * rely) * radius - pt.x, centerY + (rely - z * relx) * radius - pt.y); - this._add(new Segment(pt, handleIn, out)); + segments.push(new Segment(pt, handleIn, out)); } angle += inc; } + // Add all segments at once at the end for higher performance + this._add(segments); }, lineBy: function(vector) { diff --git a/test/tests/Path.js b/test/tests/Path.js index 83ad7093..c2079c9a 100644 --- a/test/tests/Path.js +++ b/test/tests/Path.js @@ -3,12 +3,12 @@ module('Path'); test('path.join(path)', function() { var doc = new Document(); var path = new Path(); - path.add(0, 0); - path.add(10, 0); + path.add([0, 0]); + path.add([10, 0]); var path2 = new Path(); - path2.add(10, 0); - path2.add(20, 10); + path2.add([10, 0]); + path2.add([20, 10]); path.join(path2); compareSegmentLists(path.segments, [new Segment(new Point(0, 0)), @@ -16,37 +16,37 @@ test('path.join(path)', function() { equals(doc.activeLayer.children.length, 1); var path = new Path(); - path.add(0, 0); - path.add(10, 0); + path.add([0, 0]); + path.add([10, 0]); var path2 = new Path(); - path2.add(20, 10); - path2.add(10, 0); + path2.add([20, 10]); + path2.add([10, 0]); path.join(path2); compareSegmentLists(path.segments, [new Segment(new Point(0, 0)), new Segment(new Point(10, 0)), new Segment(new Point(20, 10))]); var path = new Path(); - path.add(0, 0); - path.add(10, 0); + path.add([0, 0]); + path.add([10, 0]); var path2 = new Path(); - path2.add(30, 10); - path2.add(40, 0); + path2.add([30, 10]); + path2.add([40, 0]); path.join(path2); compareSegmentLists(path.segments, [new Segment(new Point(0, 0)), new Segment(new Point(10, 0)), new Segment(new Point(30, 10)), new Segment(new Point(40, 0))]); var path = new Path(); - path.add(0, 0); - path.add(10, 0); - path.add(20, 10); + path.add([0, 0]); + path.add([10, 0]); + path.add([20, 10]); var path2 = new Path(); - path2.add(0, 0); - path2.add(10, 5); - path2.add(20, 10); + path2.add([0, 0]); + path2.add([10, 5]); + path2.add([20, 10]); path.join(path2); compareSegmentLists(path.segments, [new Segment(new Point(0, 0)), @@ -58,10 +58,10 @@ test('path.join(path)', function() { test('path.remove()', function() { var doc = new Document(); var path = new Path(); - path.add(0, 0); - path.add(10, 0); - path.add(20, 0); - path.add(30, 0); + path.add([0, 0]); + path.add([10, 0]); + path.add([20, 0]); + path.add([30, 0]); path.removeSegment(0); equals(path.segments.length, 3); diff --git a/test/tests/Path_Curves.js b/test/tests/Path_Curves.js index 63afff08..4b933548 100644 --- a/test/tests/Path_Curves.js +++ b/test/tests/Path_Curves.js @@ -6,44 +6,22 @@ test('path.curves Synchronisation', function() { var path = new Path(); path.add(new Point(0, 100)); - equals(path.curves.toString(), ''); - + equals(path.segments.toString(), '{ point: { x: 0, y: 100 } }', 'path.segments: path.add(new Point(0, 100));'); + equals(path.curves.toString(), '', 'path.curves: path.add(new Point(0, 100));'); path.add(new Point(100, 100)); - equals(path.curves.toString(), - '{ point1: { x: 0, y: 100 }, point2: { x: 100, y: 100 } }', - '2 x path.add()'); - - path.insert(1, { point: [50, 0], handleIn: [-25, 0], handleOut: [25, 0] }); - equals(path.curves.toString(), - '{ point1: { x: 0, y: 100 }, handle2: { x: -25, y: 0 }, point2: { x: 50, y: 0 } },{ point1: { x: 50, y: 0 }, handle1: { x: 25, y: 0 }, point2: { x: 100, y: 100 } }', - 'path.insert()' - ); - + equals(path.segments.toString(), '{ point: { x: 0, y: 100 } },{ point: { x: 100, y: 100 } }', 'path.segments: path.add(new Point(100, 100));'); + equals(path.curves.toString(), '{ point1: { x: 0, y: 100 }, point2: { x: 100, y: 100 } }', 'path.curves: path.add(new Point(100, 100));'); + path.insert(1, {point:[50, 0], handleIn:[-25, 0], handleOut:[25, 0]}); + equals(path.segments.toString(), '{ point: { x: 0, y: 100 } },{ point: { x: 50, y: 0 }, handleIn: { x: -25, y: 0 }, handleOut: { x: 25, y: 0 } },{ point: { x: 100, y: 100 } }', 'path.segments: path.insert(1, {point:[50, 0], handleIn:[-25, 0], handleOut:[25, 0]});'); + equals(path.curves.toString(), '{ point1: { x: 0, y: 100 }, handle2: { x: -25, y: 0 }, point2: { x: 50, y: 0 } },{ point1: { x: 50, y: 0 }, handle1: { x: 25, y: 0 }, point2: { x: 100, y: 100 } }', 'path.curves: path.insert(1, {point:[50, 0], handleIn:[-25, 0], handleOut:[25, 0]});'); path.closed = true; - equals(path.curves.toString(), - '{ point1: { x: 0, y: 100 }, handle2: { x: -25, y: 0 }, point2: { x: 50, y: 0 } },{ point1: { x: 50, y: 0 }, handle1: { x: 25, y: 0 }, point2: { x: 100, y: 100 } },{ point1: { x: 100, y: 100 }, point2: { x: 0, y: 100 } }', - 'path.closed = true'); - + equals(path.segments.toString(), '{ point: { x: 0, y: 100 } },{ point: { x: 50, y: 0 }, handleIn: { x: -25, y: 0 }, handleOut: { x: 25, y: 0 } },{ point: { x: 100, y: 100 } }', 'path.segments: path.closed = true;'); + equals(path.curves.toString(), '{ point1: { x: 0, y: 100 }, handle2: { x: -25, y: 0 }, point2: { x: 50, y: 0 } },{ point1: { x: 50, y: 0 }, handle1: { x: 25, y: 0 }, point2: { x: 100, y: 100 } },{ point1: { x: 100, y: 100 }, point2: { x: 0, y: 100 } }', 'path.curves: path.closed = true;'); path.removeSegments(2, 3); - equals(path.curves.toString(), - '{ point1: { x: 0, y: 100 }, handle2: { x: -25, y: 0 }, point2: { x: 50, y: 0 } },{ point1: { x: 50, y: 0 }, handle1: { x: 25, y: 0 }, point2: { x: 0, y: 100 } }', - 'path.removeSegments(2, 3)'); - - equals(path.segments.toString(), - '{ point: { x: 0, y: 100 } },{ point: { x: 50, y: 0 }, handleIn: { x: -25, y: 0 }, handleOut: { x: 25, y: 0 } }', - 'segments'); - + equals(path.segments.toString(), '{ point: { x: 0, y: 100 } },{ point: { x: 50, y: 0 }, handleIn: { x: -25, y: 0 }, handleOut: { x: 25, y: 0 } }', 'path.segments: path.removeSegments(2, 3);'); + equals(path.curves.toString(), '{ point1: { x: 0, y: 100 }, handle2: { x: -25, y: 0 }, point2: { x: 50, y: 0 } },{ point1: { x: 50, y: 0 }, handle1: { x: 25, y: 0 }, point2: { x: 0, y: 100 } }', 'path.curves: path.removeSegments(2, 3);'); path.add(new Point(100, 100)); - equals(path.curves.toString(), - '{ point1: { x: 0, y: 100 }, handle2: { x: -25, y: 0 }, point2: { x: 50, y: 0 } },{ point1: { x: 50, y: 0 }, handle1: { x: 25, y: 0 }, point2: { x: 100, y: 100 } },{ point1: { x: 100, y: 100 }, point2: { x: 0, y: 100 } }', - 'path.add()'); - path.removeSegments(1, 2); - equals(path.curves.toString(), - '{ point1: { x: 0, y: 100 }, point2: { x: 100, y: 100 } },{ point1: { x: 100, y: 100 }, point2: { x: 0, y: 100 } }', - 'path.removeSegments(1, 2)'); - - equals(path.segments.toString(), - '{ point: { x: 0, y: 100 } },{ point: { x: 100, y: 100 } }', - 'segments'); + equals(path.segments.toString(), '{ point: { x: 0, y: 100 } },{ point: { x: 100, y: 100 } }', 'path.segments: path.add(new Point(100, 100));\n path.removeSegments(1, 2);'); + equals(path.curves.toString(), '{ point1: { x: 0, y: 100 }, point2: { x: 100, y: 100 } },{ point1: { x: 100, y: 100 }, point2: { x: 0, y: 100 } }', 'path.curves: path.add(new Point(100, 100));\n path.removeSegments(1, 2);'); });