
// CommonStrokeTessellatorMiter.hpp - common GPU and CPU polar stroking miter handling

#ifndef __CommonStrokeTessellatorMiter_hpp__
#define __CommonStrokeTessellatorMiter_hpp__

#include "CommonStrokeTessellatorPrivate.hpp"
#include "CommonStrokeTessellatorMath.hpp"

// If a join, handle the miter-like cases (miters or square caps) properly.
float StrokeTessellatorMETHOD miterHandling(int link_type, float clamped_steps)
{
    CONST bool treat_as_miter = isJoin(link_type) && isMiterJoin(max_join_steps);
    if (treat_as_miter) {
        FOR_THREAD(3) link_state[TID] = 1;  // treat_as_miter is true.
        // Absolute angle difference.
        CONST float theta1 = theta[3];
        CONST float theta0 = theta[0];
        CONST float theta = absoluteAngleDifference(theta1, theta0);

        // Consider an (untruncated) miter join forming a pair of
        // symmetric canonical triangles (ABC & ADC below) sharing a common
        // edge AC (of length m) with a tip vertex A and join vertex C where
        // two path segments X & Y join.  The edges BC & DC have identical
        // length r, being the path's stroke radius.  AB & AD are assumed
        // unit length (1.0) for a canonical miter triangle pair.
        //
        //   tip               tip
        //   A                 A
        //   |\               /|
        //   | \             / |
        // z |  \ m  ===  m /  | z
        //   |   \         /   |
        //   B----C       C----D
        //      r           r
        //
        //   ^ triangle   ^ triangle
        //     ABC          ADC
        //
        // Imagine triangles ABC & ACD sharing their common edge AC
        // to form a quadrilateral miter region.
        //
        //   r = length(BC) = length(DC) = unit length (1.0)
        //   z = length(AB) = length(AD) = miter_extension
        //
        // ABC & ADC each have edges of length m & r and are both right
        // triangles so by the Hypotenuse-Leg theorem, ABC & ADC are
        // congruent.
        //
        // This means angles BCA & ACD (called phi) are equal.
        //
        // The angle BAC & CAD at the tip is theta/2 where theta is the angle
        // at which the tangents of the two path segments joining at C
        // arrive/depart respectively as will soon be explained.
        //
        // Now consider how the miter join is formed.  Some path segment
        // X terminates at C while a subsequent path segment Y initializes
        // at C.  The angle between the normal vector tangent to path X's
        // termination and the normal vector tangent to path segment Y's
        // initialization is theta, as pictured:
        //
        //     A        normal initializing path X
        //      \ phi D
        //       \   /
        //    phi \ / theta
        //    B----C--------- normal terminating path Y
        //  theta / \ phi
        //       /   \. 
        //      / phi \.
        //
        // Note: phi & theta are not necessarily equal.
        //
        // The diagnonal line containing A & C bisects the
        // two lines containing B & C and D & C respectively.
        // Hence angles ACB and ACD are both measure phi.
        //
        // As shown, opposite angles formed by pairs of lines intersecting at C
        // have equal angles.
        //
        // The sum of all angles meeting at C is 2 Pi radians:
        //
        //   2 Pi = phi + phi + theta + phi + phi + theta
        //        = 4 phi + 2 theta
        //
        // Therefore:
        //
        //         Pi - theta
        //   phi = ----------
        //             2
        //
        // Knowing ABC & ADC are congruent right triangles, then:
        //
        //   Pi = theta/2 + phi + Pi/2
        //
        // Therefore
        //
        //   angles ABC & ADC are right angles = Pi/2 radians
        //   angles BAC & DAC are identically = theta/2
        //   angles BCA & ACD are identitcally = phi
        //
        // Now we can compute z, the length of edges AB & AD:
        //
        //   tan(phi) = z/r
        //   tan(Pi/2 - theta/2) = z/r
        //
        // Apply identity: tan(Pi/2 - x) = cot(x)
        //
        //   cot(theta/2) = z/r
        //   tan(theta/2) = r/z
        //
        //                                  sin(theta)
        // Apply identity: tan(theta/2) = --------------
        //                                1 + cos(theta)
        //
        // hence
        //
        //        sin(theta)
        //   z = -------------- = miter_extension
        //       1 + cos(theta)
        //
        float miter_extension = sin(theta)/(1+cos(theta));

        CONST float winding = cos(theta1)*sin(theta0) - cos(theta0) * sin(theta1);
        CONST bool miter_limit_exceeded = miter_extension > effective_miter_limit;

        if (miter_limit_exceeded) {
            if (isMiterTruncateJoin(max_join_steps)) {
                // Miter truncate forces the miter_extension to be effective_miter_limit.
                miter_extension = effective_miter_limit;
                clamped_steps = 3; // miter truncated

                // Compute offset to next rib's truncated tip and store in cp[2].
                vec2 next_tangent = vec2(cos(theta1), sin(theta1));
                CONST vec2 next_normal = ortho(next_tangent);
                if (winding < 0) {
                    next_tangent *= -1;
                }
                // Stash normalized offset in cp[2]
                FOR_THREAD(2) cp[TID].xy = next_normal + miter_extension*next_tangent;
                // NOTE: in non-AFFINE case, cp[2].z not accessed in evaluation shader for join
            } else {
                // MiterRevert: limit exceeded so revert to bevel.
                clamped_steps = 1; // bevel
            }
        } else {
            clamped_steps = 2; // miter with tip
        }

        // Compute offset to tip (or previous rib's truncated tip) and store in cp[1].
        vec2 prev_tangent = vec2(cos(theta0), sin(theta0));
        CONST vec2 prev_normal = ortho(prev_tangent);
        if (winding < 0) {
            prev_tangent *= -1;
        }

        // Stash normalized offset in cp[1]
        FOR_THREAD(1) cp[TID].xy = prev_normal - miter_extension*prev_tangent;
        // NOTE: in non-AFFINE case, cp[1].z not accessed in evaluation shader for join
    } else {
        if (isCap(link_type)) {
            if (isSquare(link_type)) {
                // Yes, stash square corners away in cp[1] and cp[2].
                FOR_THREAD(3) link_state[TID] = -1;  // treat_as_miter is false AND square
                clamped_steps = 3;  // Square caps always need 3 steps.

                CONST float theta0 = theta[0];
                CONST vec2 prev_tangent = vec2(cos(theta0), sin(theta0));
                CONST vec2 prev_normal = ortho(prev_tangent);

                FOR_THREAD(2) cp[TID].xy = -prev_normal - prev_tangent;
                FOR_THREAD(1) cp[TID].xy = prev_normal - prev_tangent;
                // NOTE: in non-AFFINE case, cp[1].z & cp[2].z not accessed in evaluation shader for join
            } else if (isTriangular(link_type)) {
                clamped_steps = 2;  // Triangular caps always need 2 steps.
            } else {
                // No, must be None, Round, or Triangular cap.
                clamped_steps = min(linkTypeToClampedSteps(link_type), clamped_steps);
            }
        } else {
            // Else is a join...
            // All non-miter join cases: clamp to max_join_steps.
            // 0 for none, 1 for bevel, 2 for triangle, large value for round.
            clamped_steps = min(float(max_join_steps), clamped_steps);
        }
    }
    return clamped_steps;
}

#endif // __CommonStrokeTessellatorMiter_hpp__
