convert method
dynamic
convert()
Implementation
convert() {
var numPoints = points.length;
if (numPoints < 2) return 0;
var isClosed = points[0].equals(points[numPoints - 1]);
var previousPoint = points[0];
var nextPoint;
var strokeWidth2 = style["strokeWidth"] / 2;
var deltaU = 1 / (numPoints - 1);
bool innerSideModified = false;
bool joinIsOnLeftSide = false;
bool isMiter = false;
bool initialJoinIsOnLeftSide = false;
num u1 = 0;
// Get initial left and right stroke points
getNormal(points[0], points[1], tempV2_1).multiplyScalar(strokeWidth2);
lastPointL.copy(points[0]).sub(tempV2_1);
lastPointR.copy(points[0]).add(tempV2_1);
point0L.copy(lastPointL);
point0R.copy(lastPointR);
for (var iPoint = 1; iPoint < numPoints; iPoint++) {
currentPoint = points[iPoint];
// Get next point
if (iPoint == numPoints - 1) {
if (isClosed) {
// Skip duplicated initial point
nextPoint = points[1];
} else {
nextPoint = null;
}
} else {
nextPoint = points[iPoint + 1];
}
// Normal of previous segment in tempV2_1
var normal1 = tempV2_1;
getNormal(previousPoint, currentPoint, normal1);
tempV2_3.copy(normal1).multiplyScalar(strokeWidth2);
currentPointL.copy(currentPoint).sub(tempV2_3);
currentPointR.copy(currentPoint).add(tempV2_3);
u1 = u0 + deltaU;
innerSideModified = false;
if (nextPoint != null) {
// Normal of next segment in tempV2_2
getNormal(currentPoint, nextPoint, tempV2_2);
tempV2_3.copy(tempV2_2).multiplyScalar(strokeWidth2);
nextPointL.copy(currentPoint).sub(tempV2_3);
nextPointR.copy(currentPoint).add(tempV2_3);
joinIsOnLeftSide = true;
tempV2_3.subVectors(nextPoint, previousPoint);
if (normal1.dot(tempV2_3) < 0) {
joinIsOnLeftSide = false;
}
if (iPoint == 1) initialJoinIsOnLeftSide = joinIsOnLeftSide;
tempV2_3.subVectors(nextPoint, currentPoint);
tempV2_3.normalize();
var dot = Math.abs(normal1.dot(tempV2_3));
// If path is straight, don't create join
if (dot != 0) {
// Compute inner and outer segment intersections
var miterSide = strokeWidth2 / dot;
tempV2_3.multiplyScalar(-miterSide);
tempV2_4.subVectors(currentPoint, previousPoint);
tempV2_5.copy(tempV2_4).setLength(miterSide).add(tempV2_3);
innerPoint.copy(tempV2_5).negate();
var miterLength2 = tempV2_5.length();
var segmentLengthPrev = tempV2_4.length();
tempV2_4.divideScalar(segmentLengthPrev);
tempV2_6.subVectors(nextPoint, currentPoint);
var segmentLengthNext = tempV2_6.length();
tempV2_6.divideScalar(segmentLengthNext);
// Check that previous and next segments doesn't overlap with the innerPoint of intersection
if (tempV2_4.dot(innerPoint) < segmentLengthPrev && tempV2_6.dot(innerPoint) < segmentLengthNext) {
innerSideModified = true;
}
outerPoint.copy(tempV2_5).add(currentPoint);
innerPoint.add(currentPoint);
isMiter = false;
if (innerSideModified) {
if (joinIsOnLeftSide) {
nextPointR.copy(innerPoint);
currentPointR.copy(innerPoint);
} else {
nextPointL.copy(innerPoint);
currentPointL.copy(innerPoint);
}
} else {
// The segment triangles are generated here if there was overlapping
makeSegmentTriangles(u1);
}
switch (style["strokeLineJoin"]) {
case 'bevel':
makeSegmentWithBevelJoin(joinIsOnLeftSide, innerSideModified, u1, u1);
break;
case 'round':
// Segment triangles
createSegmentTrianglesWithMiddleSection(joinIsOnLeftSide, innerSideModified, u1);
// Join triangles
if (joinIsOnLeftSide) {
makeCircularSector(currentPoint, currentPointL, nextPointL, u1, 0);
} else {
makeCircularSector(currentPoint, nextPointR, currentPointR, u1, 1);
}
break;
case 'miter':
case 'miter-clip':
default:
var miterFraction = (strokeWidth2 * style["strokeMiterLimit"]) / miterLength2;
if (miterFraction < 1) {
// The join miter length exceeds the miter limit
if (style["strokeLineJoin"] != 'miter-clip') {
makeSegmentWithBevelJoin(joinIsOnLeftSide, innerSideModified, u1, u1);
break;
} else {
// Segment triangles
createSegmentTrianglesWithMiddleSection(joinIsOnLeftSide, innerSideModified, u1);
// Miter-clip join triangles
if (joinIsOnLeftSide) {
tempV2_6.subVectors(outerPoint, currentPointL).multiplyScalar(miterFraction).add(currentPointL);
tempV2_7.subVectors(outerPoint, nextPointL).multiplyScalar(miterFraction).add(nextPointL);
addVertex(currentPointL, u1, 0);
addVertex(tempV2_6, u1, 0);
addVertex(currentPoint, u1, 0.5);
addVertex(currentPoint, u1, 0.5);
addVertex(tempV2_6, u1, 0);
addVertex(tempV2_7, u1, 0);
addVertex(currentPoint, u1, 0.5);
addVertex(tempV2_7, u1, 0);
addVertex(nextPointL, u1, 0);
} else {
tempV2_6.subVectors(outerPoint, currentPointR).multiplyScalar(miterFraction).add(currentPointR);
tempV2_7.subVectors(outerPoint, nextPointR).multiplyScalar(miterFraction).add(nextPointR);
addVertex(currentPointR, u1, 1);
addVertex(tempV2_6, u1, 1);
addVertex(currentPoint, u1, 0.5);
addVertex(currentPoint, u1, 0.5);
addVertex(tempV2_6, u1, 1);
addVertex(tempV2_7, u1, 1);
addVertex(currentPoint, u1, 0.5);
addVertex(tempV2_7, u1, 1);
addVertex(nextPointR, u1, 1);
}
}
} else {
// Miter join segment triangles
if (innerSideModified) {
// Optimized segment + join triangles
if (joinIsOnLeftSide) {
addVertex(lastPointR, u0, 1);
addVertex(lastPointL, u0, 0);
addVertex(outerPoint, u1, 0);
addVertex(lastPointR, u0, 1);
addVertex(outerPoint, u1, 0);
addVertex(innerPoint, u1, 1);
} else {
addVertex(lastPointR, u0, 1);
addVertex(lastPointL, u0, 0);
addVertex(outerPoint, u1, 1);
addVertex(lastPointL, u0, 0);
addVertex(innerPoint, u1, 0);
addVertex(outerPoint, u1, 1);
}
if (joinIsOnLeftSide) {
nextPointL.copy(outerPoint);
} else {
nextPointR.copy(outerPoint);
}
} else {
// Add extra miter join triangles
if (joinIsOnLeftSide) {
addVertex(currentPointL, u1, 0);
addVertex(outerPoint, u1, 0);
addVertex(currentPoint, u1, 0.5);
addVertex(currentPoint, u1, 0.5);
addVertex(outerPoint, u1, 0);
addVertex(nextPointL, u1, 0);
} else {
addVertex(currentPointR, u1, 1);
addVertex(outerPoint, u1, 1);
addVertex(currentPoint, u1, 0.5);
addVertex(currentPoint, u1, 0.5);
addVertex(outerPoint, u1, 1);
addVertex(nextPointR, u1, 1);
}
}
isMiter = true;
}
break;
}
} else {
// The segment triangles are generated here when two consecutive points are collinear
makeSegmentTriangles(u1);
}
} else {
// The segment triangles are generated here if it is the ending segment
makeSegmentTriangles(u1);
}
if (!isClosed && iPoint == numPoints - 1) {
// Start line endcap
addCapGeometry(points[0], point0L, point0R, joinIsOnLeftSide, true, u0);
}
// Increment loop variables
u0 = u1;
previousPoint = currentPoint;
lastPointL.copy(nextPointL);
lastPointR.copy(nextPointR);
}
if (!isClosed) {
// Ending line endcap
addCapGeometry(currentPoint, currentPointL, currentPointR, joinIsOnLeftSide, false, u1);
} else if (innerSideModified) {
// Modify path first segment vertices to adjust to the segments inner and outer intersections
var lastOuter = outerPoint;
var lastInner = innerPoint;
if (initialJoinIsOnLeftSide != joinIsOnLeftSide) {
lastOuter = innerPoint;
lastInner = outerPoint;
}
if (joinIsOnLeftSide) {
if (isMiter || initialJoinIsOnLeftSide) {
lastInner.toArray(vertices, 0 * 3);
lastInner.toArray(vertices, 3 * 3);
if (isMiter) {
lastOuter.toArray(vertices, 1 * 3);
}
}
} else {
if (isMiter || !initialJoinIsOnLeftSide) {
lastInner.toArray(vertices, 1 * 3);
lastInner.toArray(vertices, 3 * 3);
if (isMiter) {
lastOuter.toArray(vertices, 0 * 3);
}
}
}
}
return numVertices;
// -- End of algorithm
}