private static void AddExtremeVertex(List <Double2> vertices, double halfWidth, Double2 x, double entryAngle, double exitAngle, bool startVertex) { var offset = halfWidth * Double2.FromAngle((startVertex ? exitAngle : entryAngle) + Pi_2); if (!startVertex) { offset = -offset; } // There are two cases to process on the start point: // When the angles are equal, there is no need to generate the "gap" to be filled by the joint if (RoughlyEquals(exitAngle, entryAngle)) { vertices.Add(x + offset); vertices.Add(x - offset); } // When the angles are different, we generate the perpendicular bisector else { // The sign difference between the entry angle and the previous curve's exit angle will tell // where the angle bisector will need to be put var diff = (exitAngle - entryAngle).WrapAngle(); var bisectorOffset = halfWidth / Math.Cos(Math.Abs(diff) / 2) * Double2.FromAngle(entryAngle + diff / 2 + Pi_2); if (!startVertex) { bisectorOffset = -bisectorOffset; } // If the difference is positive, the bisector is to the right (i.e. AFTER the first point) if (startVertex == (diff > 0)) { vertices.Add(x + bisectorOffset); vertices.Add(x); vertices.Add(x - offset); } // If it is negative, the bisector is to the left (i.e. BEFORE the point) else { vertices.Add(x + offset); vertices.Add(x); vertices.Add(x - bisectorOffset); } } }
private static void GenerateLineJoints(List <Triangle> triangles, List <CurveTriangle> curveTriangles, Curve prevCurve, Curve nextCurve, double halfWidth, StrokeLineJoin lineJoin, double miterLimit) { // First, calculate the difference between the angles to check where the joint need to be formed var exitAngle = prevCurve.ExitAngle; var entryAngle = nextCurve.EntryAngle; var diff = (exitAngle - entryAngle).WrapAngle(); var sd = Math.Sign(diff); // Skip creating the joint if the diff is small enough if (RoughlyZero(diff)) { return; } // The common point and the offset vectors var p = (prevCurve.At(1) + nextCurve.At(0)) / 2; var entryOffset = sd * halfWidth * Double2.FromAngle(entryAngle + Pi_2); var exitOffset = sd * halfWidth * Double2.FromAngle(exitAngle + Pi_2); // Calculate the bisector and miter length var miter = halfWidth / Math.Cos(Math.Abs(diff) / 2); var bisectorOffset = sd * miter * Double2.FromAngle(entryAngle + diff / 2 + Pi_2); // Utility function for miter and round Double2[] GenerateClippedTriangle(bool forRound) { var miterWidth = halfWidth * (forRound ? 1f : miterLimit); if (miter < miterWidth) { return new[] { Double2.Zero, entryOffset, bisectorOffset, exitOffset } } ; else { // Clip the miter var p1 = entryOffset + miterWidth * (bisectorOffset - entryOffset) / miter; var p2 = exitOffset + miterWidth * (bisectorOffset - exitOffset) / miter; return(new[] { Double2.Zero, entryOffset, p1, p2, exitOffset }); } } // Now, create the next triangles if necessary switch (lineJoin) { case StrokeLineJoin.Bevel: // Create the bevel triangle triangles.Add(new Triangle(p, p + entryOffset, p + exitOffset)); break; case StrokeLineJoin.Miter: case StrokeLineJoin.MiterClip: { // Check the conditions for the miter (only clip if miter-clip is explicity selected) if (lineJoin == StrokeLineJoin.Miter && miter >= halfWidth * miterLimit) { break; } // Generate the miter var polygon = GenerateClippedTriangle(false).Select(v => p + v).ToArray(); triangles.AddRange(Triangle.MakeTriangleFan(polygon)); break; } case StrokeLineJoin.Round: { // Generate the round triangle var curvePolygon = GenerateClippedTriangle(true) .Select(v => new CurveVertex(p + v, new Double4(v.X, v.Y, -v.Y, 1f))).ToArray(); curveTriangles.AddRange(CurveVertex.MakeTriangleFan(curvePolygon)); break; } case StrokeLineJoin.Arcs: { // Compute the curvatures of the curves var exitKappa = prevCurve.ExitCurvature; var entryKappa = nextCurve.EntryCurvature; // If both of them are zero, fall back to miter if (RoughlyZero(exitKappa) && RoughlyZero(entryKappa)) { goto case StrokeLineJoin.MiterClip; } throw new NotImplementedException("Later i'll end it"); } break; default: break; } }
public static DoubleMatrix Rotate(double angle) { var rot = Double2.FromAngle(angle); return(new DoubleMatrix(rot.X, rot.Y, -rot.Y, rot.X, 0, 0)); }