@@ -63,18 +63,52 @@ QuadricShape ::IsIntersectedByRay(const PointType & rayOrigin,
6363 const ScalarType zero = itk::NumericTraits<ScalarType>::ZeroValue ();
6464 if (Aq == zero)
6565 {
66- // Only one intersection with, e.g., a plane: check which half line should be kept
67- nearDist = -Cq / Bq;
68- // The following condition tests on which side of the quadric is the ray origin.
69- // It is equivalent to the following code.
70- // if ((IsInsideQuadric(rayOrigin) && nearDist < 0.) ||
71- // (!IsInsideQuadric(rayOrigin) && nearDist > 0.))
72- if (Cq * nearDist > 0 .)
73- farDist = itk::NumericTraits<ScalarType>::max ();
66+ if (Bq == zero)
67+ {
68+ if (Cq == zero)
69+ {
70+ // Whole ray contained in quadric
71+ nearDist = -itk::NumericTraits<ScalarType>::max ();
72+ farDist = itk::NumericTraits<ScalarType>::max ();
73+ }
74+ else
75+ return false ;
76+ }
7477 else
7578 {
76- farDist = nearDist;
77- nearDist = -itk::NumericTraits<ScalarType>::max ();
79+ if (Cq == zero)
80+ {
81+ // rayOrigin is on the quadric, we need to find which half line is in
82+ // the quadric For t=1, we have Aq+Bq+Cq, in this case Bq. As Aq and Cq
83+ // are negative, we test the sign of Bq.
84+ if (Bq > 0 )
85+ {
86+ // rayOrigin+rayDirection is not in the quadric
87+ farDist = 0 .;
88+ nearDist = -itk::NumericTraits<ScalarType>::max ();
89+ }
90+ else
91+ {
92+ nearDist = 0 .;
93+ farDist = itk::NumericTraits<ScalarType>::max ();
94+ }
95+ }
96+ else
97+ {
98+ // Only one intersection with, e.g., a plane: check which half line should be kept
99+ nearDist = -Cq / Bq;
100+ // The following condition tests on which side of the quadric is the ray origin.
101+ // It is equivalent to the following code.
102+ // if ((IsInsideQuadric(rayOrigin) && nearDist < 0.) ||
103+ // (!IsInsideQuadric(rayOrigin) && nearDist > 0.))
104+ if (Cq * nearDist > 0 .)
105+ farDist = itk::NumericTraits<ScalarType>::max ();
106+ else
107+ {
108+ farDist = nearDist;
109+ nearDist = -itk::NumericTraits<ScalarType>::max ();
110+ }
111+ }
78112 }
79113 }
80114 else
@@ -83,7 +117,12 @@ QuadricShape ::IsIntersectedByRay(const PointType & rayOrigin,
83117 // The epsilon value allows detection of very close intersections, i.e., a
84118 // ray tangent to the quadric
85119 static constexpr ScalarType eps = 1e5 * itk::NumericTraits<ScalarType>::epsilon ();
86- if (discriminant <= eps)
120+ if (itk::Math::abs (discriminant) <= eps)
121+ {
122+ nearDist = -Bq / (2 * Aq);
123+ farDist = nearDist;
124+ }
125+ else if (discriminant < zero)
87126 {
88127 // No intersection but one might be dealing with an infinite line
89128 // in the quadric, e.g. a line parallel to and in a cylinder.
@@ -92,52 +131,54 @@ QuadricShape ::IsIntersectedByRay(const PointType & rayOrigin,
92131 {
93132 nearDist = -itk::NumericTraits<ScalarType>::max ();
94133 farDist = itk::NumericTraits<ScalarType>::max ();
95- return ApplyClipPlanes (rayOrigin, rayDirection, nearDist, farDist);
96134 }
97135 else
98136 return false ;
99137 }
100- nearDist = (-Bq - sqrt (discriminant)) / (2 * Aq);
101- farDist = (-Bq + sqrt (discriminant)) / (2 * Aq);
102- if (nearDist > farDist)
103- std::swap (nearDist, farDist);
104-
105- // Check if the segment between the two intersections is in the quadric.
106- // Instead of testing if the central point is oustside the quadric with
107- // !IsInsideQuadric(rayOrigin + 0.5 * (farDist + nearDist) * rayDirection),
108- // which was prone to numerical errors, we test if the ray origin is between
109- // intersections (farDist * nearDist < 0) and strictly in the quadric (Cq < 0),
110- // or before / after the two intersections (farDist * nearDist > 0) and outside
111- // the quadric (Cq>0).
112- if (Cq * farDist * nearDist < zero)
138+ else
113139 {
114- // If not, one is dealing with a half line, searching for the good one (out of two)
115- double tmpNearDist = -itk::NumericTraits<ScalarType>::max ();
116- double tmpFarDist = itk::NumericTraits<ScalarType>::max ();
117- if (!ApplyClipPlanes (rayOrigin, rayDirection, tmpNearDist, tmpFarDist))
118- return false ;
119- if (tmpFarDist > farDist)
140+ nearDist = (-Bq - sqrt (discriminant)) / (2 * Aq);
141+ farDist = (-Bq + sqrt (discriminant)) / (2 * Aq);
142+ if (nearDist > farDist)
143+ std::swap (nearDist, farDist);
144+
145+ // Check if the segment between the two intersections is in the quadric.
146+ // Instead of testing if the central point is oustside the quadric with
147+ // !IsInsideQuadric(rayOrigin + 0.5 * (farDist + nearDist) * rayDirection),
148+ // which was prone to numerical errors, we test if the ray origin is between
149+ // intersections (farDist * nearDist < 0) and strictly in the quadric (Cq < 0),
150+ // or before / after the two intersections (farDist * nearDist > 0) and outside
151+ // the quadric (Cq>0).
152+ if (Cq * farDist * nearDist < zero)
120153 {
121- if (tmpNearDist < nearDist)
154+ // If not, one is dealing with a half line, searching for the good one (out of two)
155+ double tmpNearDist = -itk::NumericTraits<ScalarType>::max ();
156+ double tmpFarDist = itk::NumericTraits<ScalarType>::max ();
157+ if (!ApplyClipPlanes (rayOrigin, rayDirection, tmpNearDist, tmpFarDist))
158+ return false ;
159+ if (tmpFarDist > farDist)
122160 {
123- itkGenericExceptionMacro (<< " Intersection of the quadric with the line "
124- << " gives two half lines, add clip planes to select which one" );
161+ if (tmpNearDist < nearDist)
162+ {
163+ itkGenericExceptionMacro (<< " Intersection of the quadric with the line "
164+ << " gives two half lines, add clip planes to select which one" );
165+ }
166+ else
167+ {
168+ nearDist = std::max (farDist, tmpNearDist);
169+ farDist = tmpFarDist;
170+ return true ;
171+ }
125172 }
126- else
173+ else if (tmpNearDist < nearDist)
127174 {
128- nearDist = std::max (farDist, tmpNearDist );
129- farDist = tmpFarDist ;
175+ farDist = std::min (nearDist, tmpFarDist );
176+ nearDist = tmpNearDist ;
130177 return true ;
131178 }
179+ else
180+ return false ;
132181 }
133- else if (tmpNearDist < nearDist)
134- {
135- farDist = std::min (nearDist, tmpFarDist);
136- nearDist = tmpNearDist;
137- return true ;
138- }
139- else
140- return false ;
141182 }
142183 }
143184
0 commit comments