convert method

int convert()

Implementation

int convert() {
  final numPoints = points.length;

  if (numPoints < 2) return 0;

  final isClosed = points[0].equals(points[numPoints - 1]);

  Vector2 previousPoint = points[0];
  Vector2? nextPoint;

  final strokeWidth2 = style["strokeWidth"] / 2;

  final 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).scale(strokeWidth2);
  lastPointL.setFrom(points[0]).sub(tempV2_1);
  lastPointR.setFrom(points[0]).add(tempV2_1);
  point0L.setFrom(lastPointL);
  point0R.setFrom(lastPointR);

  for (int 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
    final normal1 = tempV2_1;
    getNormal(previousPoint, currentPoint, normal1);

    tempV2_3.setFrom(normal1).scale(strokeWidth2);
    currentPointL.setFrom(currentPoint).sub(tempV2_3);
    currentPointR.setFrom(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.setFrom(tempV2_2).scale(strokeWidth2);
      nextPointL.setFrom(currentPoint).sub(tempV2_3);
      nextPointR.setFrom(currentPoint).add(tempV2_3);

      joinIsOnLeftSide = true;
      tempV2_3.sub2(nextPoint, previousPoint);
      if (normal1.dot(tempV2_3) < 0) {
        joinIsOnLeftSide = false;
      }

      if (iPoint == 1) initialJoinIsOnLeftSide = joinIsOnLeftSide;

      tempV2_3.sub2(nextPoint, currentPoint);
      tempV2_3.normalize();
      final dot = normal1.dot(tempV2_3).abs();

      // If path is straight, don't create join
      if (dot != 0) {
        // Compute inner and outer segment intersections
        final miterSide = strokeWidth2 / dot;
        tempV2_3.scale(-miterSide);
        tempV2_4.sub2(currentPoint, previousPoint);
        tempV2_5.setFrom(tempV2_4).setLength(miterSide).add(tempV2_3);
        innerPoint.setFrom(tempV2_5).negate();
        final miterLength2 = tempV2_5.length;
        final segmentLengthPrev = tempV2_4.length;
        tempV2_4.divideScalar(segmentLengthPrev);
        tempV2_6.sub2(nextPoint, currentPoint);
        final 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.setFrom(tempV2_5).add(currentPoint);
        innerPoint.add(currentPoint);

        isMiter = false;

        if (innerSideModified) {
          if (joinIsOnLeftSide) {
            nextPointR.setFrom(innerPoint);
            currentPointR.setFrom(innerPoint);
          } else {
            nextPointL.setFrom(innerPoint);
            currentPointL.setFrom(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:
            final 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.sub2(outerPoint, currentPointL)
                      .scale(miterFraction)
                      .add(currentPointL);
                  tempV2_7.sub2(outerPoint, nextPointL)
                      .scale(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.sub2(outerPoint, currentPointR)
                      .scale(miterFraction)
                      .add(currentPointR);
                  tempV2_7.sub2(outerPoint, nextPointR)
                      .scale(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.setFrom(outerPoint);
                } else {
                  nextPointR.setFrom(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.setFrom(nextPointL);
    lastPointR.setFrom(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

    Vector2 lastOuter = outerPoint;
    Vector2 lastInner = innerPoint;

    if (initialJoinIsOnLeftSide != joinIsOnLeftSide) {
      lastOuter = innerPoint;
      lastInner = outerPoint;
    }

    if (joinIsOnLeftSide) {
      if (isMiter || initialJoinIsOnLeftSide) {
        lastInner.copyIntoArray(vertices, 0 * 3);
        lastInner.copyIntoArray(vertices, 3 * 3);

        if (isMiter) {
          lastOuter.copyIntoArray(vertices, 1 * 3);
        }
      }
    } else {
      if (isMiter || !initialJoinIsOnLeftSide) {
        lastInner.copyIntoArray(vertices, 1 * 3);
        lastInner.copyIntoArray(vertices, 3 * 3);

        if (isMiter) {
          lastOuter.copyIntoArray(vertices, 0 * 3);
        }
      }
    }
  }

  return numVertices;

  // -- End of algorithm
}