Defect reported by Claude Sonnet5/Fable5. The std::vector member
mProjVertices occurs in a loop over all faces. It stores the projections
onto a plane which are later processed. The member is resized each time the current faceIndices has a larger number of elements that mProjVertices. There is no clear call, so if the number of current faceIndices is smaller than that of mProjVertices, the ensuing code accesses elements of mProjVertices that were set for the previous triangles. I removed the mProjVertices member and now have local storage for the projection vertices that is created for each incoming face. While I was in there, I refactored the code in an attempt to simply
the class interface. There is only one face data structure used for triangles, convex polygons, and simple polygons. Consequently, the class has a single constructor to which you pass a parameter specifying the type of face to be processed. I factored out shared code for ContainsC1C2 and ContainsS1 into SharedContains.
Claude Sonnet 5 reported a defect in ApprConvexQuadByRect.h. It
appeared to be a false positive. However, I analyzed the code and re-read the PDF for the fitting algorithm (Fit a Convex Quadrilateral by a Rectangle). The second equality in equation (5) of the PDF is horribly wrong. Moreover, the PDF is nearly impossible to read and understand. I removed the header file from the GTE source code and I removed the PDF from the documentation database. The motivation for the algorithm was based on user request, to approximate a nearly
rectangular quadrilateral by a rectangle. It is simpler to use the
minimum-area bounding rectangle code (\Code{MininumAreaBox2.h}).
Defect reported by Claude Sonnet5/Fable5. In the Find function that
uses bisection, if the loop involving maxIterations is encountered and
maxIterations is zero, root is unassigned and the return value is true. The caller believes a root is found but accesses uninitialized memory. I added a trap for maxIterations being zero before the loop is reached; if zero, the function exits. In all the conditions where there is no
root computed, root is assigned zero to avoid uninitialized memory.
Defect reported by Claude Sonnet5/Fable5. The AddTriangle function
tests whether a triangle is in a set. If it is not, the function has nothing
to do and exits. If it is, a test is applied to see whether the to-be-inserted triangle has a duplicate in the set; this triangle has opposite winding order, so the function swaps the last two vertices of the input triangle. If there is no duplicate, the triangle is added to the set. However, the last two vertices had been swapped. They need to be swapped back to the original order of the input triangle.
Defect reported by Claude Sonnet5/Fable5. There is no defect. The minimum spanning tree data structure contains a sentinel followed by the tree. The sentinel is {nil,vertexIndex}, where vertexIndex is the
index into the vertex array corresponding to the first vertex visited by
the tree construction. I added comments about this in hopes later Claude runs will not flag this as a defect.
Defect found by Claude Sonnet5/Fable5. The degree-16 constants in
C_ROTC4_EST_COEFF} have an entry +2.505210838484547384e-08 which is missing a terminating constant. The compiler adds the next constant to it, in which case the last constant of the array is implicitly zero. I added the comma.
Defect found by Claude Sonnet5/Fable5. This is actually a warning about potential numerical issues in ToCoefficients, the variation accepting an array of numbers. The warning was about skipping a loop index when trying to determine a number to divide all the coefficients to transform them to a range containing floating-point 1. I redesigned this to divide by the maximum-magnitude coefficient of the quadratic terms. I also removed some comments about Microsoft Visual Studio 2019 code analysis generating incorrect warnings.
Defect found by Claude Sonnet5/Fable5. In the second derivative computations of NURBSEighthSphereDegree4, the tempDuu, tempDuv, and tempDvv equations had a leading multiplication by D. This is incorrect, so the leading D multiplications were removed. I found a second bug that Claude did not detect. In the first derivative computations, Bu[1][3] was computed as (Real)4 * vv. This should be
(Real)4 * v * vv. After fixing the bugs, I implemented the NURBS code
using Mathematica 15.0.1.0 and verified that the GTE/GTL C++ code produces correct results.
Defect found by Claude Sonnet5/Fable5. When I added the class
NURBSCircularArcDegree2, I introduced a regression in the class
NURBSQuarterCircleDegree2. For some unknown reason, the control points of NURBSQuarterCircleDegree2 were modified from {(1,0), (1,1), (0,1)} to {(1,1),(1,1),(1,1)}. Probably a copy-and-forgot-to-modify error.
Defect found by Claude Sonnet5/Fable5. FitUsingSquaredLengths has a loop that terminates if the number of iterations exceeds maxIterations specified by the caller. The old return value is ++iteration, which is maxIterations+1 on non-convergence. I now return iteration.
I had fixed a bug in the bounding volume tree code for GTE; see the August 1, 2026 update notes. Unfortunately, I had not fixed the bug in the GTL code. A regression was introduced when I backported the GTL code to GTE. I fixed this.
I backported the bounding volume tree code from GTL to GTE. GTE now supports trees for points, segments, or triangles. Part of the backport involved refactoring the classes to share more code, making the derived tree classes simpler to write. The file ApprCone3EllipseAndPoints.h was modified to support the new oriented box tree code. In the process of testing with the sample application, I encountered an exception: press key `3' followed by `b'.
An array of shared pointers of meshes is created in CreateScene with a reserve call followed by multiple push_back calls. However, CreateScene is called multiple times (pressing keys to change the
test mesh). The array winds up having several null pointers, which causes the graphics engine Draw call to throw an exception. The fix was to add a clear call after the reserve call.
Defect found by Claude Sonnet5/Fable5. The function BisectionConverged compared fMin <= fMax. It needs to compare std::fabs(fMin) <= std::fabs(fMax); otherwise, the result is the same endpoint regardless of which is actually closer to the root. This can lead to a 1 ULP error in nearest floating-point number.
The file uses LogAssert. For some reason previous compiles allowed
access to this even though there is no include of Logger.h. Now the
compiler does complain (perhaps a difference in MSVS 2022 and MSVS 2026). I added the include.
Defect found by Claude Sonnet5/Fable5. The function P2D5 called P3D4 but should call P3D5. Modified the code and verified the
correctness using Mathematica.
Defect found by Claude Sonnet5/Fable5. In GetGradient, the gradient[2] term uses (oneMinusY,OneMinusY) for the weights. These should be (oneMinusY,fy).
Defect found by Claude Sonnet5/Fable5. Function ImageUtility3::Dilate has a design different from that of ImageUtility2::Dilate. The 3D version failed to set boundary voxels to 1 when a neighboring voxel is 1. I rewrote ImageUtility3::Dilate to match the design of the 2D version. While I was in there, I added the 3D morphology functions for Erode, Open, and Close. I also moved the 2D and 3D component labelers to public scope because they might be useful in some applications. Finally, I reformatted both the 2D and 3D files to match the interface designs.
Defect found by Claude Sonnet5/Fable5. In the CreateMesh function, the line of code for tNumExtra has a division by rMin. For a finite cone with hMin of zero, there is a division by zero which leads to tNumExtra of positive infinity. I modified rMax/rMin to (1+rMax)/(1+rMin) to avoid the division by zero. I also added a TODO about determining how I derived the tNumExtra equation.
Defect found by Claude Sonnet5/Fable5. The Execute functions of
BVTreeOfTriangles and OBBTreeOfTriangles create
std::vector<size_t> indexStack(2 * this->mHeight)}. If the input tree has height of zero, the index stack is empty, so the code indexStack[0] = 0 crashes. The number of index stack elements must be 2 * this->mHeight + 1.
Defect found by Claude Sonnet5/Fable5. The following constants differ from the correctly rounded IEEE floating-point numbers: GTE_C_INV_TWO_PI differs by 2 ULP, GTE_C_INV_HALF_PI} differs by 1 ULP, and GTE_C_DEG_TO_RAD differs by 1 ULP. I computed the correctly rounded numbers using rational arithmetic and Machin's formula [pi = 16 atan(1/5) - 4 atan(1/239)]. The power series terms were partially summed until the rounded double-precision values between two consecutive partial sums were equal.
Defect found by Claude Sonnet5/Fable5. The find-intersection query has a division by segExtent. If the segment is degenerate, representing a single point (p[0] and p[1] are the same point), the segment extent is zero whereby the query has a division by zero. Additionally, the parameter value is zero, so result.parameter[i] / segExtent is
indeterminate (0/0). I added a guard against this case which calls a point-in-box query when the segment is degenerate. Claude's analysis did not report a second problem. The DoQuery method does not fill in the result members for index 1. When the projection intervals touch in a single point (numIntersections is 1), I increment this to 2 in case the caller references those values (undefined behavior without this).
The same division-by-zero problem occurs in the segment-oriented-box code. I also added a guard against this case.
Defect found by Claude Sonnet5/Fable5. DoQueryInfiniteCylinder has a division by distance, which leads to an indeterminate form when
cylinder.radius is zero. Exception handling was added to throw when
the radius is not positive. Also, DoQueryFiniteCylinder now throws an exception when the height is not positive.
Defect found by Claude Sonnet5/Fable5. The edge-edge double loop had P1=tetra0.v[edge1Indices[0]]. The wrong tetrahedron is accessed. It
should be tetra1.
Defect found by Claude Sonnet5/Fable5. ComputeVOrthogonal has a loop with upper bound mNumCols-3. This works for matrices with 3 or more columns, but it fails when the number of columns is 2. The `col' index wraps to SIZE_MAX and the result is a crash when trying to reference an empty matrix. I added code to execute the loop only when mNumCols is 3 or larger.
I thought the negations of unsigned integers in the constructors with input 'number' were fixed. Running my instantiation tests showed that there is still a bug. The negative has to occur before the static cast, not after.
Changes to CMakeLists.txt files. Based on CMake warnings, increased the minimum required cmake version to 3.10 from 3.8. Modified the GTE_MINOR_VERSION to 2.
I added Microsoft Visual Studio 2026 files for solutions, projects, and
filters. There are nearly 400 such triples of files (.v18.sln, .v18.vcxproj,
.v18.vcxproj.filters).
Added intersection queries for a triangle and a canonical box or a triangle and an aligned box. The code for a triangle and an oriented box already existed. Modified the sizes and positions of the triangle and oriented box in the sample application; the previous triangle was too small and the previous box was too large.
Despite using Mathematica to verify the mathematical equations and updating the PDF for box-cylinder intersection, I still failed to fix the bug mentioned in the December 26, 2025 report. In fact, the previous report broke the case for (U2,-D). The case for (D,-U2) had an incorrect divisor. These have now been fixed.
[From December 26] Fixed the lower and upper calculations for case (U2,-D). Thanks to
OttoX at github for reporting associated bugs.
GaussianElimination.h: The private Set function had an if-else statement that was designed to provide fast copying for floating-point Real and object copying for rational Real. The if-else statement provides flow control at run time. However, the separation must occur at compile time. The Ubuntu g++ 13.3.0 compiler generated an error for the separation. I modified the code to use std::enable_if and provided a Set for each case, the other case ignored by SFINAE (Substitution Failure Is Not An Error).
MinimumVolumeBox3*.h: The g++ compiler warned about the use of a pragma that is supported by the Microsoft Visual Studio compiler. With treat-warnings-as-errors, the files do not compile. I removed the pragma statements. The g++ compiler also complained about the Edge.T and Triangle.T members shadowing the class template parameter T. I renamed the members of Edge and Triangle to use lower-case v, e, and t.
MinimumVolumeBox3DWindow3.cpp: The modifications to the minimum volume box code required an update to the sample application. The new template parameter list is different from the old one.