// File: /workspace/github_cpp_makefile_star2_O1/tomfunkhouser[P]gaps/pkgs/R3Shapes/R3Isect.cpp
// Function: gaps::R3Intersects(gaps::R3Ray const&, gaps::R3Cylinder const&, gaps::R3Point*, gaps::R3Vector*, double*)
RNClassID R3Intersects(const R3Ray& ray, const R3Cylinder& cylinder, 
    R3Point *hit_point1, R3Vector *hit_normal1, RNScalar *hit_t1)
{
    // Check if sphere contains ray start point
    RNBoolean start_inside = R3Contains(cylinder, ray.Start());
    if (start_inside) {
      if (hit_point1) *hit_point1 = ray.Start();
      if (hit_normal1) *hit_normal1 = -ray.Vector();
      if (hit_t1) *hit_t1 = 0;
      return R3_SPAN_CLASS_ID;
    }

    // See Graphics Gems IV, page 356
    // Compute parametric values of intersection with infinite cylinder
    RNScalar cyl_t1, cyl_t2;
    R3Vector R = ray.Vector();
    R3Vector A = cylinder.Axis().Vector();
    R3Vector D = R % A;
    RNScalar a = D.Length();
    if (RNIsZero(a)) {
	// Ray and axis are parallel
	RNScalar d = R3Distance(ray.Start(), cylinder.Axis().Line());
	if (RNIsLessOrEqual(d, cylinder.Radius())) {
	    // Ray lies entirely inside infinite cylinder
	    cyl_t1 = 0.0;
	    cyl_t2 = RN_INFINITY;
	}
	else {
	    // Ray lies entirely outside infinite cylinder
	    return RN_NULL_CLASS_ID;
	}
    }
    else {
	// Ray and axis are not parallel
	// Compute distance from axis to closest point on ray's line
	D /= a;
	R3Vector RC = ray.Start() - cylinder.Axis().Start();
	RNScalar d = RC.Dot(D);
	if (d < 0.0) d = -d;
	if (RNIsGreater(d, cylinder.Radius())) {
	    // Ray does not intersect infinite cylinder
	    return RN_NULL_CLASS_ID;
	}
	else {
	    // Find parametric value (cyl_t) of point on ray closest to axis
	    assert(RNIsNotZero(a));
	    RNScalar t = (RC % A).Dot(D) / -a;
	    
	    // Find parametric value delta (s) to intersection points
	    RNScalar s;
	    R3Vector O = D % A;
	    O.Normalize();
	    RNScalar b = cylinder.Radius() * cylinder.Radius() - d*d;
	    if (RNIsPositive(b)) {
		// Crossing span intersection
		RNScalar e = R.Dot(O);
		assert(RNIsNotZero(e));
		s = sqrt(b) / e;
		if (s < 0.0) s = -s;
	    }
	    else {
		// Grazing point intersection
		s = 0.0;
	    }
	    
	    // Find parametric value (cyl_t2) of second intersection
	    cyl_t2 = t + s;
	    if (RNIsNegative(cyl_t2)) {
		// Intersection point is behind ray
		return RN_NULL_CLASS_ID;
	    }
	    else {
		// Find parametric value (cyl_t1) of first intersection
		cyl_t1 = t - s;
		
		// Check if ray start is in infinite cylinder
		if (cyl_t1 < 0.0) cyl_t1 = 0.0;
	    }
	}
    }
	
    // Compute parametric values of intersection with caps
    RNScalar cap_t1 = 0, cap_t2 = 0;
    RNScalar dot = ray.Vector().Dot(cylinder.Axis().Vector());
    RNScalar d_top = R3SignedDistance(cylinder.Top().Plane(), ray.Start());
    RNScalar d_base = R3SignedDistance(cylinder.Base().Plane(), ray.Start());
    if (RNIsPositive(d_top)) {
	// Ray starts above top cap
	if (RNIsPositiveOrZero(dot)) {
	    // Ray points upward or orthogonally from above cylinder top
	    return RN_NULL_CLASS_ID;
	}
	else {
	    // Ray points downward from above cylinder top
	    if ((R3Intersects(ray, cylinder.Top().Plane(), NULL, &cap_t1)) &&
		(RNIsGreater(cap_t1, cyl_t2))) {
		// Ray misses cylinder
		return RN_NULL_CLASS_ID;
	    }
	    else if ((R3Intersects(ray, -(cylinder.Base().Plane()), NULL, &cap_t2)) &&
		     (RNIsLess(cap_t2, cyl_t1))) {
		// Ray misses cylinder
		return RN_NULL_CLASS_ID;
	    }
	    else if (RNIsGreater(cap_t1, cyl_t1)) {
		// Ray hits top cap 
		assert(cap_t1 >= 0.0);
		if (hit_t1) *hit_t1 = cap_t1;
		if (hit_point1) *hit_point1 = ray.Point(cap_t1);
		if (hit_normal1) *hit_normal1 = cylinder.Top().Normal();
		return R3_POINT_CLASS_ID;
	    }
	    else {
		// Ray hits side of cylinder
	    }
	}
    }
    else if (RNIsPositive(d_base)) {
	// Ray starts below base cap
	if (RNIsNegativeOrZero(dot)) {
	    // Ray points downward or orthogonally
	    return RN_NULL_CLASS_ID;
	}
	else {
	    // Ray points upward from below cylinder base
	    if ((R3Intersects(ray, cylinder.Base().Plane(), NULL, &cap_t1)) &&
		(RNIsGreater(cap_t1, cyl_t2))) {
		// Ray misses cylinder
		return RN_NULL_CLASS_ID;
	    }
	    else if ((R3Intersects(ray, -(cylinder.Top().Plane()), NULL, &cap_t2)) &&
		     (RNIsLess(cap_t2, cyl_t1))) {
		// Ray misses cylinder
		return RN_NULL_CLASS_ID;
	    }
	    else if (RNIsGreater(cap_t1, cyl_t1)) {
		// Ray hits base cap 
		assert(cap_t1 >= 0.0);
		if (hit_t1) *hit_t1 = cap_t1;
		if (hit_point1) *hit_point1 = ray.Point(cap_t1);
		if (hit_normal1) *hit_normal1 = cylinder.Base().Normal();
		return R3_POINT_CLASS_ID;
	    }
	    else {
		// Ray hits side of cylinder
	    }
	}
    }
    else {
	// Ray starts on or between caps
	if (RNIsPositive(dot)) {
	    if (R3Intersects(ray, -(cylinder.Top().Plane()), NULL, &cap_t1)) {
		if (RNIsLess(cap_t1, cyl_t1)) {
		    // Intersection with infinite cylinder is beyond cap
		    return RN_NULL_CLASS_ID;
		}
	    }
	}
	else if (RNIsNegative(dot)) {
	    if (R3Intersects(ray, -(cylinder.Base().Plane()), NULL, &cap_t1)) {
		if (RNIsLess(cap_t1, cyl_t1)) {
		    // Intersection with infinite cylinder is beyond cap
		    return RN_NULL_CLASS_ID;
		}
	    }
	}
    }

    // Ray hit side of cylinder
    assert(cyl_t1 >= 0.0);
    if (hit_t1) *hit_t1 = cyl_t1;
    if (hit_point1) *hit_point1 = ray.Point(cyl_t1);
    if (hit_normal1) {
	R3Point p, *H;
	if (hit_point1) H = hit_point1;
	else { p = ray.Point(cyl_t1); H = &p; }
        R3Vector HB = *H - cylinder.Axis().Start();
	*hit_normal1 = (HB - HB.Dot(A) * A) / cylinder.Radius();
    }
    return R3_POINT_CLASS_ID;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x138, %rsp            # imm = 0x138
movq %r8, %r13
movq %rcx, %r15
movq %rdx, %rbx
movq %rsi, %r12
movq %rdi, %r14
movq %rsi, %rdi
movq %r14, %rsi
callq 0x498d4
testl %eax, %eax
je 0x44434
testq %rbx, %rbx
je 0x443ea
movq %rbx, %rdi
movq %r14, %rsi
callq 0x3cd94
testq %r15, %r15
je 0x4440e
addq $0x18, %r14
leaq 0x70(%rsp), %rbx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x3e154
movq %r15, %rdi
movq %rbx, %rsi
callq 0x3dc6a
movl $0x4, %ebp
testq %r13, %r13
je 0x44420
movq $0x0, (%r13)
movl %ebp, %eax
addq $0x138, %rsp            # imm = 0x138
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %r13, 0x20(%rsp)
movq %rbx, 0x30(%rsp)
movq %r15, 0x38(%rsp)
leaq 0x18(%r14), %rsi
leaq 0xd8(%rsp), %rbp
movq %rbp, %rdi
movq %rsi, 0x40(%rsp)
callq 0x3d4ce
leaq 0x8(%r12), %rax
movq %rax, 0x58(%rsp)
leaq 0x20(%r12), %r15
leaq 0xa8(%rsp), %r13
movq %r13, %rdi
movq %r15, %rsi
callq 0x3d4ce
leaq 0xc0(%rsp), %rbx
movq %rbx, %rdi
movq %rbp, %rsi
movq %r13, %rdx
callq 0x3de12
movq %rbx, %rdi
callq 0x3d5c4
leaq 0xa16f5(%rip), %rbx     # 0xe5b98
movsd (%rbx), %xmm2
movapd 0x5db71(%rip), %xmm1    # 0xa2020
xorpd %xmm2, %xmm1
ucomisd %xmm1, %xmm0
jb 0x44508
ucomisd %xmm0, %xmm2
jb 0x44508
movq %r14, %rdi
movq 0x58(%rsp), %rsi
callq 0x49f22
subsd 0x78(%r12), %xmm0
movsd (%rbx), %xmm1
xorl %ebp, %ebp
ucomisd %xmm0, %xmm1
movq 0x20(%rsp), %r13
jb 0x44420
leaq 0xa16b9(%rip), %rax     # 0xe5ba8
movsd (%rax), %xmm0
movsd %xmm0, 0x50(%rsp)
xorpd %xmm0, %xmm0
movsd %xmm0, 0x10(%rsp)
jmp 0x446b9
leaq 0xc0(%rsp), %rbx
movq %rbx, %rdi
movapd %xmm0, 0x60(%rsp)
callq 0x3e0ec
leaq 0x70(%rsp), %r13
movq %r13, %rdi
movq %r14, %rsi
movq 0x58(%rsp), %rdx
callq 0x3cc88
movq %r13, %rdi
movq %rbx, %rsi
leaq 0xa1658(%rip), %rbx     # 0xe5b98
callq 0x3d756
movapd 0x5dad3(%rip), %xmm1    # 0xa2020
xorpd %xmm0, %xmm1
maxsd %xmm0, %xmm1
movapd %xmm1, %xmm0
subsd 0x78(%r12), %xmm0
xorl %ebp, %ebp
ucomisd (%rbx), %xmm0
ja 0x4463f
leaq 0x90(%rsp), %rbx
leaq 0x70(%rsp), %rsi
leaq 0xa8(%rsp), %rdx
movq %rbx, %rdi
movapd %xmm1, 0x10(%rsp)
callq 0x3de12
leaq 0xc0(%rsp), %r13
movq %rbx, %rdi
movq %r13, %rsi
callq 0x3d756
movapd 0x60(%rsp), %xmm1
xorpd 0x5da70(%rip), %xmm1    # 0xa2020
divsd %xmm1, %xmm0
movsd %xmm0, 0x60(%rsp)
leaq 0x90(%rsp), %rbx
movq %rbx, %rdi
movq %r13, %rsi
leaq 0xa8(%rsp), %rdx
callq 0x3de12
movq %rbx, %rdi
leaq 0xa15b9(%rip), %rbx     # 0xe5b98
callq 0x3d7e0
movsd 0x78(%r12), %xmm2
movapd 0x10(%rsp), %xmm0
mulsd %xmm0, %xmm0
mulsd %xmm2, %xmm2
subsd %xmm0, %xmm2
xorpd %xmm1, %xmm1
ucomisd (%rbx), %xmm2
jbe 0x44671
leaq 0xd8(%rsp), %rdi
leaq 0x90(%rsp), %rsi
movsd %xmm2, 0x10(%rsp)
callq 0x3d756
movsd 0x10(%rsp), %xmm1
movapd %xmm0, %xmm2
xorpd %xmm0, %xmm0
ucomisd %xmm0, %xmm1
jb 0x44648
xorps %xmm0, %xmm0
sqrtsd %xmm1, %xmm0
jmp 0x4465d
xorl %eax, %eax
movq 0x20(%rsp), %r13
jmp 0x446b1
movapd %xmm1, %xmm0
movsd %xmm2, 0x10(%rsp)
callq 0xe340
movsd 0x10(%rsp), %xmm2
divsd %xmm2, %xmm0
movapd 0x5d9b7(%rip), %xmm1    # 0xa2020
xorpd %xmm0, %xmm1
maxsd %xmm0, %xmm1
movsd 0x60(%rsp), %xmm3
movapd %xmm3, %xmm2
addsd %xmm1, %xmm2
movsd (%rbx), %xmm0
xorpd 0x5d995(%rip), %xmm0    # 0xa2020
movsd %xmm2, 0x50(%rsp)
ucomisd %xmm2, %xmm0
setbe %al
movq 0x20(%rsp), %r13
ja 0x446b1
subsd %xmm1, %xmm3
xorpd %xmm0, %xmm0
maxsd %xmm3, %xmm0
movsd %xmm0, 0x10(%rsp)
testb %al, %al
je 0x44420
xorl %ebp, %ebp
movq %rbp, 0x8(%rsp)
movq %rbp, 0x48(%rsp)
movq 0x40(%rsp), %rdi
movq %r15, %rsi
callq 0x3d756
movsd %xmm0, 0x40(%rsp)
leaq 0xc8(%r12), %rdi
movq %rdi, 0x28(%rsp)
movq %r14, %rsi
callq 0x4a10f
movsd %xmm0, 0x60(%rsp)
leaq 0x80(%r12), %r15
movq %r15, %rdi
movq %r14, %rsi
callq 0x4a10f
movsd (%rbx), %xmm1
movsd 0x60(%rsp), %xmm2
ucomisd %xmm1, %xmm2
ja 0x44764
movsd 0x40(%rsp), %xmm2
ucomisd %xmm1, %xmm0
ja 0x44837
ucomisd %xmm1, %xmm2
ja 0x448d7
xorpd 0x5d8e8(%rip), %xmm1    # 0xa2020
ucomisd %xmm2, %xmm1
jbe 0x449c8
leaq 0x70(%rsp), %rbx
movq %rbx, %rdi
movq %r15, %rsi
callq 0x46d78
xorl %ebp, %ebp
leaq 0x8(%rsp), %rcx
movq %r14, %rdi
movq %rbx, %rsi
jmp 0x448f6
xorpd 0x5d8b4(%rip), %xmm1    # 0xa2020
movsd 0x40(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jae 0x44420
xorl %ebp, %ebp
leaq 0x8(%rsp), %rcx
movq %r14, %rdi
movq 0x28(%rsp), %rsi
xorl %edx, %edx
callq 0x435e3
testl %eax, %eax
je 0x447b3
movsd 0x8(%rsp), %xmm0
subsd 0x50(%rsp), %xmm0
leaq 0xa13ef(%rip), %rax     # 0xe5b98
ucomisd (%rax), %xmm0
ja 0x44420
leaq 0x90(%rsp), %r13
movq %r13, %rdi
movq %r15, %rsi
callq 0x3e154
movsd 0x98(%r12), %xmm0
xorpd 0x5d848(%rip), %xmm0    # 0xa2020
leaq 0x70(%rsp), %r15
movq %r15, %rdi
movq %r13, %rsi
callq 0x3b582
xorl %ebp, %ebp
leaq 0x48(%rsp), %rcx
movq %r14, %rdi
movq %r15, %rsi
xorl %edx, %edx
callq 0x435e3
testl %eax, %eax
je 0x44933
movsd 0x48(%rsp), %xmm0
subsd 0x10(%rsp), %xmm0
leaq 0xa1381(%rip), %rax     # 0xe5b98
movsd (%rax), %xmm1
xorpd 0x5d7fd(%rip), %xmm1    # 0xa2020
ucomisd %xmm0, %xmm1
movq 0x20(%rsp), %r13
ja 0x44420
jmp 0x44938
ucomisd %xmm2, %xmm1
jae 0x44420
xorl %ebp, %ebp
leaq 0x8(%rsp), %rcx
movq %r14, %rdi
movq %r15, %rsi
xorl %edx, %edx
callq 0x435e3
testl %eax, %eax
je 0x44876
movsd 0x8(%rsp), %xmm0
subsd 0x50(%rsp), %xmm0
leaq 0xa132c(%rip), %rax     # 0xe5b98
ucomisd (%rax), %xmm0
ja 0x44420
leaq 0x70(%rsp), %r13
movq %r13, %rdi
movq 0x28(%rsp), %rsi
callq 0x46d78
xorl %ebp, %ebp
leaq 0x48(%rsp), %rcx
movq %r14, %rdi
movq %r13, %rsi
xorl %edx, %edx
callq 0x435e3
testl %eax, %eax
je 0x449a2
movsd 0x48(%rsp), %xmm0
subsd 0x10(%rsp), %xmm0
leaq 0xa12e1(%rip), %rax     # 0xe5b98
movsd (%rax), %xmm1
xorpd 0x5d75d(%rip), %xmm1    # 0xa2020
ucomisd %xmm0, %xmm1
movq 0x20(%rsp), %r13
ja 0x44420
jmp 0x449a7
leaq 0x70(%rsp), %r15
movq %r15, %rdi
movq 0x28(%rsp), %rsi
callq 0x46d78
xorl %ebp, %ebp
leaq 0x8(%rsp), %rcx
movq %r14, %rdi
movq %r15, %rsi
xorl %edx, %edx
callq 0x435e3
testl %eax, %eax
je 0x449c8
movsd 0x8(%rsp), %xmm0
subsd 0x10(%rsp), %xmm0
leaq 0xa1280(%rip), %rax     # 0xe5b98
movsd (%rax), %xmm1
xorpd 0x5d6fc(%rip), %xmm1    # 0xa2020
ucomisd %xmm0, %xmm1
ja 0x44420
jmp 0x449c8
movq 0x20(%rsp), %r13
movsd 0x8(%rsp), %xmm0
movapd %xmm0, %xmm1
subsd 0x10(%rsp), %xmm1
leaq 0xa1249(%rip), %rax     # 0xe5b98
ucomisd (%rax), %xmm1
jbe 0x449c8
testq %r13, %r13
je 0x44960
movsd %xmm0, (%r13)
movq 0x30(%rsp), %r12
testq %r12, %r12
je 0x44985
leaq 0x70(%rsp), %r15
movq %r15, %rdi
movq %r14, %rsi
callq 0x3c626
movq %r12, %rdi
movq %r15, %rsi
callq 0x3cd94
movl $0x1, %ebp
movq 0x38(%rsp), %rdi
testq %rdi, %rdi
je 0x44420
movq 0x28(%rsp), %rsi
jmp 0x44ac8
movq 0x20(%rsp), %r13
movsd 0x8(%rsp), %xmm0
movapd %xmm0, %xmm1
subsd 0x10(%rsp), %xmm1
leaq 0xa11da(%rip), %rax     # 0xe5b98
ucomisd (%rax), %xmm1
ja 0x44ad2
testq %r13, %r13
je 0x449d9
movsd 0x10(%rsp), %xmm0
movsd %xmm0, (%r13)
movq 0x30(%rsp), %r13
testq %r13, %r13
movq 0x38(%rsp), %r15
je 0x44a09
leaq 0x70(%rsp), %rbx
movq %rbx, %rdi
movq %r14, %rsi
movsd 0x10(%rsp), %xmm0
callq 0x3c626
movq %r13, %rdi
movq %rbx, %rsi
callq 0x3cd94
movl $0x1, %ebp
testq %r15, %r15
je 0x44420
leaq 0x70(%rsp), %rbx
movq %rbx, %rdi
callq 0x3ca24
movq 0x30(%rsp), %rsi
testq %rsi, %rsi
jne 0x44a55
leaq 0x90(%rsp), %r15
movq %r15, %rdi
movq %r14, %rsi
movsd 0x10(%rsp), %xmm0
callq 0x3c626
movq %rbx, %rdi
movq %r15, %rsi
callq 0x3cd94
movq %rbx, %rsi
leaq 0x90(%rsp), %rbx
movq %rbx, %rdi
movq 0x58(%rsp), %rdx
callq 0x3cc88
leaq 0xa8(%rsp), %r14
movq %rbx, %rdi
movq %r14, %rsi
callq 0x3d756
leaq 0xf0(%rsp), %r15
movq %r15, %rdi
movq %r14, %rsi
callq 0x3de8e
leaq 0x108(%rsp), %r14
movq %r14, %rdi
movq %rbx, %rsi
movq %r15, %rdx
callq 0x3e197
movsd 0x78(%r12), %xmm0
leaq 0x120(%rsp), %rbx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x3e200
movq 0x38(%rsp), %rdi
movq %rbx, %rsi
callq 0x3dc6a
jmp 0x44420
testq %r13, %r13
je 0x44add
movsd %xmm0, (%r13)
movq 0x30(%rsp), %r12
testq %r12, %r12
je 0x44b02
leaq 0x70(%rsp), %rbx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x3c626
movq %r12, %rdi
movq %rbx, %rsi
callq 0x3cd94
movl $0x1, %ebp
movq 0x38(%rsp), %rdi
testq %rdi, %rdi
je 0x44420
movq %r15, %rsi
jmp 0x44ac8