import ShapeModifier from './BaseShapeModifier';
// import { registerModifier } from './ShapeModifiers';
import PropertyFactory from '../PropertyFactory';
import segments_length_pool from '../pooling/segments_length_pool';
import shape_pool from '../pooling/shape_pool';
import bez from '../bez';
/**
* a
*/
export default class TrimModifier extends ShapeModifier {
/**
* a
* @param {*} elem a
* @param {*} data a
*/
initModifierProperties(elem, data) {
this.s = PropertyFactory(elem, data.s, 0, 0.01, this);
this.e = PropertyFactory(elem, data.e, 0, 0.01, this);
this.o = PropertyFactory(elem, data.o, 0, 0, this);
this.sValue = 0;
this.eValue = 0;
this.getValue = this.processKeys;
this.m = data.m;
this._isAnimated = !!this.s.effectsSequence.length || !!this.e.effectsSequence.length || !!this.o.effectsSequence.length;
}
/**
* a
* @param {*} shapeData a
*/
addShapeToModifier(shapeData) {
shapeData.pathsData = [];
}
/**
* a
* @param {*} s a
* @param {*} e a
* @param {*} shapeLength a
* @param {*} addedLength a
* @param {*} totalModifierLength a
* @return {*}
*/
calculateShapeEdges(s, e, shapeLength, addedLength, totalModifierLength) {
const segments = [];
if (e <= 1) {
segments.push({
s: s,
e: e,
});
} else if (s >= 1) {
segments.push({
s: s - 1,
e: e - 1,
});
} else {
segments.push({
s: s,
e: 1,
});
segments.push({
s: 0,
e: e - 1,
});
}
const shapeSegments = [];
const len = segments.length;
for (let i = 0; i < len; i += 1) {
const segmentOb = segments[i];
if (segmentOb.e * totalModifierLength < addedLength || segmentOb.s * totalModifierLength > addedLength + shapeLength) {
continue;
} else {
let shapeS;
let shapeE;
if (segmentOb.s * totalModifierLength <= addedLength) {
shapeS = 0;
} else {
shapeS = (segmentOb.s * totalModifierLength - addedLength) / shapeLength;
}
if (segmentOb.e * totalModifierLength >= addedLength + shapeLength) {
shapeE = 1;
} else {
shapeE = ((segmentOb.e * totalModifierLength - addedLength) / shapeLength);
}
shapeSegments.push([shapeS, shapeE]);
}
}
if (!shapeSegments.length) {
shapeSegments.push([0, 0]);
}
return shapeSegments;
}
/**
* a
* @param {*} pathsData a
* @return {*}
*/
releasePathsData(pathsData) {
const len = pathsData.length;
for (let i = 0; i < len; i += 1) {
segments_length_pool.release(pathsData[i]);
}
pathsData.length = 0;
return pathsData;
}
/**
* a
* @param {*} _isFirstFrame a
*/
processShapes(_isFirstFrame) {
let s;
let e;
if (this._mdf || _isFirstFrame) {
let o = (this.o.v % 360) / 360;
if (o < 0) {
o += 1;
}
s = (this.s.v > 1 ? 1 : this.s.v < 0 ? 0 : this.s.v) + o;
e = (this.e.v > 1 ? 1 : this.e.v < 0 ? 0 : this.e.v) + o;
// if (s === e) {}
if (s > e) {
const _s = s;
s = e;
e = _s;
}
s = Math.round(s * 10000) * 0.0001;
e = Math.round(e * 10000) * 0.0001;
this.sValue = s;
this.eValue = e;
} else {
s = this.sValue;
e = this.eValue;
}
let shapePaths;
const len = this.shapes.length;
let pathsData;
let pathData;
let totalShapeLength;
let totalModifierLength = 0;
if (e === s) {
for (let i = 0; i < len; i += 1) {
this.shapes[i].localShapeCollection.releaseShapes();
this.shapes[i].shape._mdf = true;
this.shapes[i].shape.paths = this.shapes[i].localShapeCollection;
}
} else if (!((e === 1 && s === 0) || (e===0 && s === 1))) {
const segments = [];
let shapeData;
let localShapeCollection;
for (let i = 0; i < len; i += 1) {
shapeData = this.shapes[i];
// if shape hasn't changed and trim properties haven't changed, cached previous path can be used
if (!shapeData.shape._mdf && !this._mdf && !_isFirstFrame && this.m !== 2) {
shapeData.shape.paths = shapeData.localShapeCollection;
} else {
shapePaths = shapeData.shape.paths;
const jLen = shapePaths._length;
totalShapeLength = 0;
if (!shapeData.shape._mdf && shapeData.pathsData.length) {
totalShapeLength = shapeData.totalShapeLength;
} else {
pathsData = this.releasePathsData(shapeData.pathsData);
for (let j = 0; j < jLen; j += 1) {
pathData = bez.getSegmentsLength(shapePaths.shapes[j]);
pathsData.push(pathData);
totalShapeLength += pathData.totalLength;
}
shapeData.totalShapeLength = totalShapeLength;
shapeData.pathsData = pathsData;
}
totalModifierLength += totalShapeLength;
shapeData.shape._mdf = true;
}
}
let shapeS = s;
let shapeE = e;
let addedLength = 0;
let edges;
for (let i = len - 1; i >= 0; i -= 1) {
shapeData = this.shapes[i];
if (shapeData.shape._mdf) {
localShapeCollection = shapeData.localShapeCollection;
localShapeCollection.releaseShapes();
// if m === 2 means paths are trimmed individually so edges need to be found for this specific shape relative to whoel group
if (this.m === 2 && len > 1) {
edges = this.calculateShapeEdges(s, e, shapeData.totalShapeLength, addedLength, totalModifierLength);
addedLength += shapeData.totalShapeLength;
} else {
edges = [[shapeS, shapeE]];
}
const jLen = edges.length;
for (let j = 0; j < jLen; j += 1) {
shapeS = edges[j][0];
shapeE = edges[j][1];
segments.length = 0;
if (shapeE <= 1) {
segments.push({
s: shapeData.totalShapeLength * shapeS,
e: shapeData.totalShapeLength * shapeE,
});
} else if (shapeS >= 1) {
segments.push({
s: shapeData.totalShapeLength * (shapeS - 1),
e: shapeData.totalShapeLength * (shapeE - 1),
});
} else {
segments.push({
s: shapeData.totalShapeLength * shapeS,
e: shapeData.totalShapeLength,
});
segments.push({
s: 0,
e: shapeData.totalShapeLength * (shapeE - 1),
});
}
let newShapesData = this.addShapes(shapeData, segments[0]);
if (segments[0].s !== segments[0].e) {
if (segments.length > 1) {
const lastShapeInCollection = shapeData.shape.paths.shapes[shapeData.shape.paths._length - 1];
if (lastShapeInCollection.c) {
const lastShape = newShapesData.pop();
this.addPaths(newShapesData, localShapeCollection);
newShapesData = this.addShapes(shapeData, segments[1], lastShape);
} else {
this.addPaths(newShapesData, localShapeCollection);
newShapesData = this.addShapes(shapeData, segments[1]);
}
}
this.addPaths(newShapesData, localShapeCollection);
}
}
shapeData.shape.paths = localShapeCollection;
}
}
} else if (this._mdf) {
for (let i = 0; i < len; i += 1) {
// Releasign Trim Cached paths data when no trim applied in case shapes are modified inbetween.
// Don't remove this even if it's losing cached info.
this.shapes[i].pathsData.length = 0;
this.shapes[i].shape._mdf = true;
}
}
}
/**
* a
* @param {*} newPaths a
* @param {*} localShapeCollection a
*/
addPaths(newPaths, localShapeCollection) {
const len = newPaths.length;
for (let i = 0; i < len; i += 1) {
localShapeCollection.addShape(newPaths[i]);
}
}
/**
* a
* @param {*} pt1 a
* @param {*} pt2 a
* @param {*} pt3 a
* @param {*} pt4 a
* @param {*} shapePath a
* @param {*} pos a
* @param {*} newShape a
*/
addSegment(pt1, pt2, pt3, pt4, shapePath, pos, newShape) {
shapePath.setXYAt(pt2[0], pt2[1], 'o', pos);
shapePath.setXYAt(pt3[0], pt3[1], 'i', pos + 1);
if (newShape) {
shapePath.setXYAt(pt1[0], pt1[1], 'v', pos);
}
shapePath.setXYAt(pt4[0], pt4[1], 'v', pos + 1);
}
/**
* a
* @param {*} points a
* @param {*} shapePath a
* @param {*} pos a
* @param {*} newShape a
*/
addSegmentFromArray(points, shapePath, pos, newShape) {
shapePath.setXYAt(points[1], points[5], 'o', pos);
shapePath.setXYAt(points[2], points[6], 'i', pos + 1);
if (newShape) {
shapePath.setXYAt(points[0], points[4], 'v', pos);
}
shapePath.setXYAt(points[3], points[7], 'v', pos + 1);
}
/**
* a
* @param {*} shapeData a
* @param {*} shapeSegment a
* @param {*} shapePath a
* @return {*}
*/
addShapes(shapeData, shapeSegment, shapePath) {
const pathsData = shapeData.pathsData;
const shapePaths = shapeData.shape.paths.shapes;
const len = shapeData.shape.paths._length;
let addedLength = 0;
let currentLengthData;
let segmentCount;
let lengths;
let segment;
const shapes = [];
let initPos;
let newShape = true;
if (!shapePath) {
shapePath = shape_pool.newElement();
segmentCount = 0;
initPos = 0;
} else {
segmentCount = shapePath._length;
initPos = shapePath._length;
}
shapes.push(shapePath);
for (let i = 0; i < len; i += 1) {
lengths = pathsData[i].lengths;
shapePath.c = shapePaths[i].c;
const jLen = shapePaths[i].c ? lengths.length : lengths.length + 1;
let j = 1;
for (; j < jLen; j +=1) {
currentLengthData = lengths[j-1];
if (addedLength + currentLengthData.addedLength < shapeSegment.s) {
addedLength += currentLengthData.addedLength;
shapePath.c = false;
} else if (addedLength > shapeSegment.e) {
shapePath.c = false;
break;
} else {
if (shapeSegment.s <= addedLength && shapeSegment.e >= addedLength + currentLengthData.addedLength) {
this.addSegment(shapePaths[i].v[j - 1], shapePaths[i].o[j - 1], shapePaths[i].i[j], shapePaths[i].v[j], shapePath, segmentCount, newShape);
newShape = false;
} else {
segment = bez.getNewSegment(shapePaths[i].v[j - 1], shapePaths[i].v[j], shapePaths[i].o[j - 1], shapePaths[i].i[j], (shapeSegment.s - addedLength)/currentLengthData.addedLength, (shapeSegment.e - addedLength)/currentLengthData.addedLength, lengths[j-1]);
this.addSegmentFromArray(segment, shapePath, segmentCount, newShape);
// this.addSegment(segment.pt1, segment.pt3, segment.pt4, segment.pt2, shapePath, segmentCount, newShape);
newShape = false;
shapePath.c = false;
}
addedLength += currentLengthData.addedLength;
segmentCount += 1;
}
}
if (shapePaths[i].c && lengths.length) {
currentLengthData = lengths[j - 1];
if (addedLength <= shapeSegment.e) {
const segmentLength = lengths[j - 1].addedLength;
if (shapeSegment.s <= addedLength && shapeSegment.e >= addedLength + segmentLength) {
this.addSegment(shapePaths[i].v[j - 1], shapePaths[i].o[j - 1], shapePaths[i].i[0], shapePaths[i].v[0], shapePath, segmentCount, newShape);
newShape = false;
} else {
segment = bez.getNewSegment(shapePaths[i].v[j - 1], shapePaths[i].v[0], shapePaths[i].o[j - 1], shapePaths[i].i[0], (shapeSegment.s - addedLength) / segmentLength, (shapeSegment.e - addedLength) / segmentLength, lengths[j - 1]);
this.addSegmentFromArray(segment, shapePath, segmentCount, newShape);
// this.addSegment(segment.pt1, segment.pt3, segment.pt4, segment.pt2, shapePath, segmentCount, newShape);
newShape = false;
shapePath.c = false;
}
} else {
shapePath.c = false;
}
addedLength += currentLengthData.addedLength;
segmentCount += 1;
}
if (shapePath._length) {
shapePath.setXYAt(shapePath.v[initPos][0], shapePath.v[initPos][1], 'i', initPos);
shapePath.setXYAt(shapePath.v[shapePath._length - 1][0], shapePath.v[shapePath._length - 1][1], 'o', shapePath._length - 1);
}
if (addedLength > shapeSegment.e) {
break;
}
if (i < len - 1) {
shapePath = shape_pool.newElement();
newShape = true;
shapes.push(shapePath);
segmentCount = 0;
}
}
return shapes;
}
}