Add support for insertion of multiple segments at once to Path#_add(), #add() and #insert(), and change code that relies on these methods.

This commit is contained in:
Jürg Lehni 2011-05-04 18:42:40 +01:00
parent bdbbca487f
commit a5099fd51d
4 changed files with 116 additions and 129 deletions

View file

@ -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;
}
};

View file

@ -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) {

View file

@ -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);

View file

@ -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);');
});