From 834cfc3d1ac31e838985c5aab8cf02b9f72ef7c5 Mon Sep 17 00:00:00 2001 From: Anson Biggs Date: Tue, 5 Apr 2022 16:43:36 -0700 Subject: [PATCH] made tests like way better --- src/stlProcess.jl | 2 +- test/runtests.jl | 63 ++++++++++-------- test/test_assets/2_4_8_cuboid.stl | Bin 0 -> 684 bytes test/test_assets/README.md | 27 ++++++++ .../test_assets/{cubeblender.stl => cube.stl} | Bin test/test_assets/cylinder.stl | Bin 0 -> 6284 bytes test/test_assets/slender_y.stl | Bin 0 -> 6284 bytes test/test_assets/sphere.stl | Bin 0 -> 48084 bytes 8 files changed, 62 insertions(+), 30 deletions(-) create mode 100644 test/test_assets/2_4_8_cuboid.stl create mode 100644 test/test_assets/README.md rename test/test_assets/{cubeblender.stl => cube.stl} (100%) create mode 100644 test/test_assets/cylinder.stl create mode 100644 test/test_assets/slender_y.stl create mode 100644 test/test_assets/sphere.stl diff --git a/src/stlProcess.jl b/src/stlProcess.jl index b286539..1d036c3 100644 --- a/src/stlProcess.jl +++ b/src/stlProcess.jl @@ -74,7 +74,7 @@ function get_mass_properties(triangles; scale=1) inertia[2, 3] = inertia[3, 2] = -(intg[9] - volume .* center_of_gravity[2] .* center_of_gravity[3]) inertia[1, 3] = inertia[3, 1] = -(intg[10] - volume .* center_of_gravity[3] .* center_of_gravity[1]) - return Properties(volume, center_of_gravity, inertia) + return Properties(volume, center_of_gravity, inertia ./ volume) end function fast_volume(triangles; scale=1) diff --git a/test/runtests.jl b/test/runtests.jl index 17eed18..e9b9518 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,6 +1,7 @@ using Test using stlProcess +import stlProcess.Properties using FileIO using MeshIO @@ -45,37 +46,41 @@ function _check_volume(triangles; scale=1) return volume end -@testset "simple cube stl" begin - """ - inertia math: - https://hepweb.ucsd.edu/ph110b/110b_notes/node26.html +@testset "3D Models" begin + I_mat = Matrix(I, 3, 3) + center = [0, 0, 0] - Cube is a standard cube with a length of 2 for each side. - """ - cube_path = raw"test_assets\cubeblender.stl" - stl = load(cube_path) + models = Dict( + # Inertia math: https://en.wikipedia.org/wiki/List_of_moments_of_inertia#List_of_3D_inertia_tensors + # Properties(volume, center_of_gravity, inertia) + "cube.stl" => Properties(2.0^3, center, I_mat .* 2^2 / 6), # l = 2 + "sphere.stl" => Properties(4 / 3 * pi, center, I_mat .* 2 / 5), # r = 1 + "2_4_8_cuboid.stl" => Properties(2 * 4 * 8, center, diagm([2^2 + 4^2, 8^2 + 2^2, 8^2 + 4^2]) ./ 12), # h, d, w = 2, 4, 8 + "slender_y.stl" => Properties(10 * π * 0.1^2, center, diagm([1, 0, 1]) .* (10^2 / 12)), # l_z = 10, r = 0.1 + "cylinder.stl" => Properties(10 * π * 1^2, center, diagm([(3 + 10^2) / 12, (3 + 10^2) / 12, 1^2 / 2])), # l_z = 10, r = 1 + ) + @testset "$model" for (model, control) in models + path = "test_assets\\$model" + stl = load(path) - @testset "get_mass_properties function" begin - props = get_mass_properties(stl) + @testset "get_mass_properties" begin + props = get_mass_properties(stl) - @test props.volume == 8.0 - @test all(props.center_of_gravity .== 0.0) - @test all(eigvals(props.inertia) .≈ (5.0 + 1 / 3)) - - @testset "get_volume function" begin - @test _check_volume(stl; scale=1) ≈ props.volume rtol = 0.01 - @test _check_volume(stl; scale=4) ≈ (4 * 2)^3 rtol = 0.01 + @test props.volume ≈ control.volume atol = 0.5 + @test props.center_of_gravity ≈ control.center_of_gravity atol = 0.01 + @test eigvals(props.inertia) ≈ eigvals(control.inertia) atol = 0.1 + end + @testset "Compare volumes with scaling" begin + for scale in 1:5 + props = get_mass_properties(stl; scale=scale) + volume = _check_volume(stl; scale=scale) + @test props.volume ≈ volume atol = 0.1 + end + end + @testset "find_volume" begin + for scale in [0.5, 1, 1.0, 10, 2 / 3] + @test fast_volume(stl; scale=find_scale(stl; desired_volume=scale)) ≈ scale + end end end - @testset "Compare volumes with scaling" begin - for scale in 1:5 - props = get_mass_properties(stl; scale=scale) - volume = _check_volume(stl; scale=scale) - - @test props.volume ≈ volume rtol = 0.01 - end - end - @testset "Find Scale" begin - @test fast_volume(stl; scale=find_scale(stl)) == 1.0 - end -end +end \ No newline at end of file diff --git a/test/test_assets/2_4_8_cuboid.stl b/test/test_assets/2_4_8_cuboid.stl new file mode 100644 index 0000000000000000000000000000000000000000..f07d1da3a97a705fafafcc7d569860b9a23a3b89 GIT binary patch literal 684 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 W(2g?~6>K5KP6)P8!It1JdES4!+a7EH literal 0 HcmV?d00001 diff --git a/test/test_assets/slender_y.stl b/test/test_assets/slender_y.stl new file mode 100644 index 0000000000000000000000000000000000000000..a7552356b7860b9fd5208da675f8d025eb71c131 GIT binary patch literal 6284 zcmbW5U2IfE6vwX$NI;R+M`9>E)QDK=?ox`d-5W!te3W1+n+7xjQcEq+O8dYA0^tFX zghCLoAR$+IDUybC*Fa0Ud#`**6GaP(iP0ut5fmj&QA~i)^_-bA?*HCJOys49{?D&7 zbIzGFGq-$QW5e3!niU0au5DOd@ZzePH7jb?J{K-3E(%%y=ihpQ=B9e07q87ou0FjX zrvHXxk32U&Dz>-l%lXlj=f}^qEXSMFS3$pLqViHMfnH+Ujv}TwyUQ|7k>uz*%`sGv zD0dI2F+Q0Zr7@V8dp4IqFR|@{5+-gg9xVG}Rbg_^nPo9lkT|uYUyadKF^Pzuh^T5U zOzsO1=q0xO{2V5B)lQ5JEz3)ex>6oP#YgmxB~QoOs(!W-@nm~`a(IvcuT$E#ht$u} zOGBz6*sirDJ!{;B5gcnj2e9wB0V_l?Ad0Rp|mwo7+%1X^juwT4B;dmQ+xxSbX-9THhlG`mc>=x8UMIrR)9b+vF&43D#}1{M#dQ9Vs^zH7MzdWmh*$w0(#s`7Rj0~I7zoaZWcJiQJkHec6cAc03b9_UO6gA z%u@Tp@pL{Yy6LjBk?@EBfnH)uK7OMr|6Fp83KC~jl{;RMsw*ZIwd$NBfnH+UovNG4ld8%cPwx*V^4s%s2=o%$*877_19uGVK{^dwRFL>X&BpPfYM*EN z%iV_V8zCn^pqJQom5KoM5_frHduWg%fC>`S=czgzFQxLr#F8x?IRtu%ZGWTs6`cm| zd$D+kbB_uV)F0Itan*O3SlPEEG&w+^m)Q0u)pzMMaED!NDW=mPg$feX=hYZ{M!rSo z2c0BR97=q0xO`oemBez^N)9#Ur%DoB{|Hmh@xXLZ49Rc90u=w)VGtrv(cX(}E)+R;h|7qn7>CSX!L~%UrW5z%Q z*MV{KkAVti5G%${pn|oFd&N(nVhHXA*d_b~D%h{EKl%w&%*y!$FcHxwj%IXpQNc3` z&qVD%L>YXju6H^rcsk>4z&|Tg@Lq!VAWfJIqJlRvyaD>hK!u`9HRO1F$EBz%Ti>ZQ zqgRfKA^3JrQCEb1O(1~^zCX-t^*f3Qj@7)n-Y!(|<%PRIkH9N`s^z=RTt!#D$&=oL zW>$qnpn`Rb6{`KsjzR^i66?)Rpn^4K#(r>JVZ~rAWXE`-CEkgOi5uT6Ftb^LEmSa@ zm?uAhiW!5mmK$}B)#duZX{eahat<(t*)e_~0u_v#p&uM8i~_DNI|f^*;F@r@St64; zdkhtv;lItQrvw!o5C4+7>8JOfi6r@5D1^;j-_RT@?An^Ry(5=EFR^X9h4X1ZH<%yk zyAQn$VyGaYSNqTTK}1_$E)npe|Kb;RS(fdC>%QhS&t|4Eo)tzSc-3s;?^ejYAVuiRxc{X%+|d}q*%CQy<6p}rKD z-|H9s{Rmbh=ju(4FJ%9$P%-P^+daNT{RApf?dn~FuRcw1KIYXeJb}u6USaa`Vn*`O zg)c8tmHd`9Hyr)OVS@AFPzF(v4yRrz_-0^#{->jhitKas9-!!^xUTfQo&9-M{1X-F zyXxj`ey?xH>}ke8MRu*amV~6-7!?{X61YzG_m3xoVyEnj04x5 zE>y7cv8J=L8rKppMFs1a*2ibtm;uqJoh&anoNQHIv&JFm4!; n?5x;A#mtK1W7hQGmE)Rlwm3%5F;sBwI5ragS>a6ZFIm>#xo~WH literal 0 HcmV?d00001 diff --git a/test/test_assets/sphere.stl b/test/test_assets/sphere.stl new file mode 100644 index 0000000000000000000000000000000000000000..6af6f2bd60e855f355699928cf277f2a1402bed3 GIT binary patch literal 48084 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 literal 0 HcmV?d00001