fix(oracle): use curvature-weighted centroid moments for case 33 (#5442)

* fix(oracle): use curvature-weighted centroid moments for case 33

* style(oracle): preserve reference JSON numeric formatting

* docs(oracle): remove transient case 33 validation note
This commit is contained in:
Benny1496
2026-10-25 02:30:39 +00:00
committed by GitHub
parent 3f4c6e4571
commit efd0e70f7d
3 changed files with 25 additions and 9 deletions
+1 -1
View File
@@ -45,7 +45,7 @@ No expected value comes from a commercial CAD product.
| 30-fillet-after-shell | freecad 1.1.4 | pass | 0.008 / 0.0025 (worst at 56.3, 35.7, 3.5) | FreeCAD (OpenCASCADE) build of recipe.json by tools/freecad-oracle/build.py: Part extrude, makeThickness shell, Part makeFillet | |
| 31-fillet-l-all-edges | freecad 1.1.4 | pass | 0.009 / 0.0018 (worst at 7.9, 38.6, 18.0) | FreeCAD (OpenCASCADE) build of recipe.json by tools/freecad-oracle/build.py: Part extrude, Part makeFillet | |
| 32-boss-plate-fillets | analytic | pass | | plate 60x60x8 + boss (r10, z 8..23) with R3 concave base and R2 convex top fillets taken as one solid of revolution: V, z-moment and lateral area from Pappus/Green on its (r,z) profile (quarter-circle fillet arcs); plate top loses the r13 disc | |
| 33-fillet-tangent-chain | analytic | pass | | obround (R8, centres 40 apart) x 10 minus R2 fillet spandrel R^2(1-pi/4) and 1 mm chamfer triangle swept round the whole loop (Pappus: section x path of its centroid, inset R(10-3pi)/(3(4-pi)) resp. c/3); surfaces likewise (fillet arc centroid inset R-2R/pi) | |
| 33-fillet-tangent-chain | analytic | pass | | obround (R8, centres 40 apart) x 10 minus R2 fillet spandrel R^2(1-pi/4) and 1 mm chamfer triangle swept round the whole loop. Swept volumes use Pappus; Z moments account for inward-offset perimeter P(u)=P-2pi*u: fillet top-depth moment P*A*d-2pi*r^4*(19/24-pi/4), A=r^2*(1-pi/4), d=r*(10-3pi)/(3*(4-pi)); bottom chamfer Z moment P*c^3/6-pi*c^4/12; surfaces use fillet arc centroid inset r-2r/pi | |
| 34-chamfer-then-fillet | freecad 1.1.4 | pass | 0.009 / 0.0022 (worst at 38.5, 5.6, 19.9) | FreeCAD (OpenCASCADE) build of recipe.json by tools/freecad-oracle/build.py: Part extrude, Part makeChamfer, Part makeFillet | |
| 35-fillet-curved-curved | freecad 1.1.4 | pass | 0.011 / 0.0024 (worst at -9.5, 5.3, 14.6) | FreeCAD (OpenCASCADE) build of recipe.json by tools/freecad-oracle/build.py: Part extrude, Part extrude join, Part makeFillet | |
| 36-corner-blend-two-radii | freecad 1.1.4 | pass | 0.012 / 0.0026 (worst at 45.4, 39.2, 26.5) | FreeCAD (OpenCASCADE) build of recipe.json by tools/freecad-oracle/build.py: Part extrude, Part makeFillet | |
@@ -1,13 +1,13 @@
{
"source": "analytic",
"method": "obround (R8, centres 40 apart) x 10 minus R2 fillet spandrel R^2(1-pi/4) and 1 mm chamfer triangle swept round the whole loop (Pappus: section x path of its centroid, inset R(10-3pi)/(3(4-pi)) resp. c/3); surfaces likewise (fillet arc centroid inset R-2R/pi)",
"method": "obround (R8, centres 40 apart) x 10 minus R2 fillet spandrel R^2(1-pi/4) and 1 mm chamfer triangle swept round the whole loop. Swept volumes use Pappus; Z moments account for inward-offset perimeter P(u)=P-2pi*u: fillet top-depth moment P*A*d-2pi*r^4*(19/24-pi/4), A=r^2*(1-pi/4), d=r*(10-3pi)/(3*(4-pi)); bottom chamfer Z moment P*c^3/6-pi*c^4/12; surfaces use fillet arc centroid inset r-2r/pi",
"body_count": 1,
"volume_mm3": 8237.12239193832,
"area_mm2": 2793.569488148386,
"center_of_mass": [
20.0,
0.0,
4.975827363940953
4.975870942023957
],
"bbox": {
"min": [
+22 -6
View File
@@ -237,11 +237,24 @@ def c33():
def path_len(inset): # perimeter of the obround inset by `inset`
return 2 * Lst + 2 * PI * (R - inset)
# Removed fillet spandrel: area R^2(1-pi/4), centroid inset d from the wall and d below the top.
# The perimeter of the inward offset shrinks as P(u) = P(0) - 2*pi*u.
# Pappus gives exact swept volumes, but using the unweighted section
# centroid for Z misses the correlation between inset u and depth v.
perimeter = path_len(0)
d = spandrel_offset(rf)
fil = MP.at(spandrel_area(rf) * path_len(d), [Lst / 2, 0, H - d])
# Removed chamfer triangle: area c^2/2, centroid inset c/3, height c/3.
cha = MP.at(ch * ch / 2 * path_len(ch / 3), [Lst / 2, 0, ch / 3])
fillet_area = spandrel_area(rf)
fillet_volume = fillet_area * path_len(d)
# Mixed first moment int(u*v dA) of square r*r minus quarter disk.
fillet_inset_depth_moment = rf ** 4 * (19 / 24 - PI / 4)
fillet_depth_moment = (perimeter * fillet_area * d
- 2 * PI * fillet_inset_depth_moment)
fil = MP.at(fillet_volume, [Lst / 2, 0,
H - fillet_depth_moment / fillet_volume])
# For the bottom chamfer, int(z dV) = P*c^3/6 - pi*c^4/12.
chamfer_volume = ch * ch / 2 * path_len(ch / 3)
chamfer_z_moment = perimeter * ch ** 3 / 6 - PI * ch ** 4 / 12
cha = MP.at(chamfer_volume, [Lst / 2, 0,
chamfer_z_moment / chamfer_volume])
mp = base - fil - cha
top = 2 * (R - rf) * Lst + PI * (R - rf) ** 2
bot = 2 * (R - ch) * Lst + PI * (R - ch) ** 2
@@ -252,8 +265,11 @@ def c33():
area = top + bot + wall + fsurf + csurf
write("33-fillet-tangent-chain",
"obround (R8, centres 40 apart) x 10 minus R2 fillet spandrel R^2(1-pi/4) and 1 mm chamfer "
"triangle swept round the whole loop (Pappus: section x path of its centroid, inset "
"R(10-3pi)/(3(4-pi)) resp. c/3); surfaces likewise (fillet arc centroid inset R-2R/pi)",
"triangle swept round the whole loop. Swept volumes use Pappus; Z moments "
"account for inward-offset perimeter P(u)=P-2pi*u: fillet top-depth moment "
"P*A*d-2pi*r^4*(19/24-pi/4), A=r^2*(1-pi/4), "
"d=r*(10-3pi)/(3*(4-pi)); bottom chamfer Z moment "
"P*c^3/6-pi*c^4/12; surfaces use fillet arc centroid inset r-2r/pi",
1, mp, area, [(-8, -8, 0), (48, 8, 10)], faces=14)