commit 0807c0286ad9ad247e0caf0e52137f4aa559511c Author: Timothy Prepscius Date: Wed Feb 25 12:36:47 2026 -0500 flatten 20260225 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..54958c9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.DS_Store +*.pyc +xcuserdata +.bin diff --git a/Core_Math.xcodeproj/project.pbxproj b/Core_Math.xcodeproj/project.pbxproj new file mode 100644 index 0000000..1706d54 --- /dev/null +++ b/Core_Math.xcodeproj/project.pbxproj @@ -0,0 +1,750 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 55; + objects = { + +/* Begin PBXBuildFile section */ + F608AAA628270475005C276B /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608AAA528270475005C276B /* main.cpp */; }; + F608AAFD2827266A005C276B /* Algorithm+Split.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608AA642826BCCE005C276B /* Algorithm+Split.cpp */; }; + F608AB02282726A5005C276B /* Algorithm+Segment.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F608AA5F2826BCCE005C276B /* Algorithm+Segment.hpp */; }; + F608AB03282726AA005C276B /* Algorithm+SimplifyCurve.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608AA5E2826BCCE005C276B /* Algorithm+SimplifyCurve.cpp */; }; + F608AB04282726AD005C276B /* Algorithm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608AA5C2826BCCE005C276B /* Algorithm.cpp */; }; + F608AB05282726B2005C276B /* Algorithm+Segment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608AA512826BCCE005C276B /* Algorithm+Segment.cpp */; }; + F608AB06282726B7005C276B /* Algorithm+Segment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608AA4F2826BCCE005C276B /* Algorithm+Segment.cpp */; }; + F608AB07282726BC005C276B /* Algorithm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608AA4B2826BCCE005C276B /* Algorithm.cpp */; }; + F643F23E2829B3FB000B8B40 /* HMatrix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F643F23C2829B3C3000B8B40 /* HMatrix.cpp */; }; + F643F23F2829B3FE000B8B40 /* Matrix3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F643F23D2829B3C4000B8B40 /* Matrix3.cpp */; }; + F646BFB32AF19E22007D898C /* FloatPack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F646BFB22AF19E1A007D898C /* FloatPack.cpp */; }; + F646BFB62AF1A018007D898C /* libCore_Zero.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F646BFB52AF1A018007D898C /* libCore_Zero.a */; }; + F646BFB82AF1C6A8007D898C /* libCore_Misc.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F646BFB72AF1C6A7007D898C /* libCore_Misc.a */; }; + F66D9E1429314376009D7D3D /* SimpleLine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F66D9E1329314330009D7D3D /* SimpleLine.cpp */; }; + F66D9E1529314377009D7D3D /* SimpleLine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F66D9E1329314330009D7D3D /* SimpleLine.cpp */; }; + F687F4A229CB1AFC00BE1F70 /* Sphere3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F687F4A129CB1AEC00BE1F70 /* Sphere3.cpp */; }; + F687F4A329CB1AFD00BE1F70 /* Sphere3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F687F4A129CB1AEC00BE1F70 /* Sphere3.cpp */; }; + F69548A528288DF3005D1B64 /* Real.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608AA542826BCCE005C276B /* Real.cpp */; }; + F6971F3F282B1229008FBD17 /* Algorithm+Segment.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F608AA5F2826BCCE005C276B /* Algorithm+Segment.hpp */; }; + F6971F41282B1229008FBD17 /* Algorithm+SimplifyCurve.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608AA5E2826BCCE005C276B /* Algorithm+SimplifyCurve.cpp */; }; + F6971F42282B1229008FBD17 /* Algorithm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608AA5C2826BCCE005C276B /* Algorithm.cpp */; }; + F6971F44282B1229008FBD17 /* HMatrix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F643F23C2829B3C3000B8B40 /* HMatrix.cpp */; }; + F6971F45282B1229008FBD17 /* Matrix3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F643F23D2829B3C4000B8B40 /* Matrix3.cpp */; }; + F6971F47282B1229008FBD17 /* Algorithm+Split.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608AA642826BCCE005C276B /* Algorithm+Split.cpp */; }; + F6971F48282B1229008FBD17 /* Real.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608AA542826BCCE005C276B /* Real.cpp */; }; + F6971F49282B1229008FBD17 /* Algorithm+Segment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608AA4F2826BCCE005C276B /* Algorithm+Segment.cpp */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + F608AAA128270475005C276B /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + F608A99C2826B7C8005C276B /* libCore_Math.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCore_Math.a; sourceTree = BUILT_PRODUCTS_DIR; }; + F608AA3E2826BCCE005C276B /* Algorithm+Split.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = "Algorithm+Split.hpp"; sourceTree = ""; }; + F608AA412826BCCE005C276B /* Algorithm.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = Algorithm.inl; sourceTree = ""; }; + F608AA442826BCCE005C276B /* Math+IO.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Math+IO.h"; sourceTree = ""; }; + F608AA452826BCCE005C276B /* Real.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = Real.inl; sourceTree = ""; }; + F608AA462826BCCE005C276B /* GTE_convert.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = GTE_convert.hpp; sourceTree = ""; }; + F608AA472826BCCE005C276B /* Algorithm.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Algorithm.h; sourceTree = ""; }; + F608AA4A2826BCCE005C276B /* FastFourier.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FastFourier.h; sourceTree = ""; }; + F608AA4B2826BCCE005C276B /* Algorithm.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Algorithm.cpp; sourceTree = ""; }; + F608AA4C2826BCCE005C276B /* Algorithm.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Algorithm.hpp; sourceTree = ""; }; + F608AA4D2826BCCE005C276B /* Algorithm+SimplifyCurve.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = "Algorithm+SimplifyCurve.hpp"; sourceTree = ""; }; + F608AA4E2826BCCE005C276B /* Algorithm+Split.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Algorithm+Split.inl"; sourceTree = ""; }; + F608AA4F2826BCCE005C276B /* Algorithm+Segment.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "Algorithm+Segment.cpp"; sourceTree = ""; }; + F608AA502826BCCE005C276B /* Real.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Real.h; sourceTree = ""; }; + F608AA512826BCCE005C276B /* Algorithm+Segment.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "Algorithm+Segment.cpp"; sourceTree = ""; }; + F608AA532826BCCE005C276B /* Math.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Math.hpp; sourceTree = ""; }; + F608AA542826BCCE005C276B /* Real.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Real.cpp; sourceTree = ""; }; + F608AA552826BCCE005C276B /* Epsilon.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Epsilon.h; sourceTree = ""; }; + F608AA572826BCCE005C276B /* Wm5.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Wm5.h; sourceTree = ""; }; + F608AA582826BCCE005C276B /* Wm5.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = Wm5.inl; sourceTree = ""; }; + F608AA592826BCCE005C276B /* Wm5.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Wm5.cpp; sourceTree = ""; }; + F608AA5A2826BCCE005C276B /* MathGlmC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MathGlmC.h; sourceTree = ""; }; + F608AA5C2826BCCE005C276B /* Algorithm.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Algorithm.cpp; sourceTree = ""; }; + F608AA5D2826BCCE005C276B /* Statistics.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Statistics.h; sourceTree = ""; }; + F608AA5E2826BCCE005C276B /* Algorithm+SimplifyCurve.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "Algorithm+SimplifyCurve.cpp"; sourceTree = ""; }; + F608AA5F2826BCCE005C276B /* Algorithm+Segment.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = "Algorithm+Segment.hpp"; sourceTree = ""; }; + F608AA612826BCCE005C276B /* Math.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Math.h; sourceTree = ""; }; + F608AA622826BCCE005C276B /* Algorithm+Segment.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Algorithm+Segment.inl"; sourceTree = ""; }; + F608AA642826BCCE005C276B /* Algorithm+Split.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "Algorithm+Split.cpp"; sourceTree = ""; }; + F608AA662826BCCE005C276B /* Zero.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Zero.h; sourceTree = ""; }; + F608AA682826BCCE005C276B /* Math.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = Math.inl; sourceTree = ""; }; + F608AAA328270475005C276B /* Core_Math_Tests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = Core_Math_Tests; sourceTree = BUILT_PRODUCTS_DIR; }; + F608AAA528270475005C276B /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + F608AB6B2827F3C5005C276B /* Makefile.def */ = {isa = PBXFileReference; lastKnownFileType = text; path = Makefile.def; sourceTree = ""; }; + F608AB6C2827F3C5005C276B /* Makefile.project */ = {isa = PBXFileReference; lastKnownFileType = text; path = Makefile.project; sourceTree = ""; }; + F608ABA7282865E8005C276B /* Real.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Real.hpp; sourceTree = ""; }; + F608ABC828287338005C276B /* Math+V.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Math+V.h"; sourceTree = ""; }; + F61F9BF52C6E506000F79137 /* Makefile.project */ = {isa = PBXFileReference; lastKnownFileType = text; path = Makefile.project; sourceTree = ""; }; + F643F2292829A919000B8B40 /* Vector3.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Vector3.hpp; sourceTree = ""; }; + F643F22A2829A9A2000B8B40 /* Vector3.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = Vector3.inl; sourceTree = ""; }; + F643F22B2829AA66000B8B40 /* Vector3.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Vector3.h; sourceTree = ""; }; + F643F22C2829AAF2000B8B40 /* HPoint.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = HPoint.hpp; sourceTree = ""; }; + F643F22D2829AB76000B8B40 /* HPoint.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = HPoint.inl; sourceTree = ""; }; + F643F22E2829AC00000B8B40 /* HPoint.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HPoint.h; sourceTree = ""; }; + F643F22F2829AD00000B8B40 /* Vector2.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Vector2.hpp; sourceTree = ""; }; + F643F2302829AD31000B8B40 /* Vector2.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = Vector2.inl; sourceTree = ""; }; + F643F2312829AF0B000B8B40 /* Matrix3.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Matrix3.hpp; sourceTree = ""; }; + F643F2322829AF5C000B8B40 /* Matrix3.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = Matrix3.inl; sourceTree = ""; }; + F643F2332829B01F000B8B40 /* Matrix3.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Matrix3.h; sourceTree = ""; }; + F643F2342829B054000B8B40 /* Sphere3.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Sphere3.hpp; sourceTree = ""; }; + F643F2352829B086000B8B40 /* Sphere1.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Sphere1.hpp; sourceTree = ""; }; + F643F2362829B0DD000B8B40 /* Sphere3.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = Sphere3.inl; sourceTree = ""; }; + F643F2372829B135000B8B40 /* Sphere3.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Sphere3.h; sourceTree = ""; }; + F643F2382829B179000B8B40 /* Sphere1.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = Sphere1.inl; sourceTree = ""; }; + F643F2392829B1DE000B8B40 /* HMatrix.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = HMatrix.hpp; sourceTree = ""; }; + F643F23A2829B216000B8B40 /* HMatrix.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HMatrix.h; sourceTree = ""; }; + F643F23B2829B23C000B8B40 /* HMatrix.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = HMatrix.inl; sourceTree = ""; }; + F643F23C2829B3C3000B8B40 /* HMatrix.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = HMatrix.cpp; sourceTree = ""; }; + F643F23D2829B3C4000B8B40 /* Matrix3.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Matrix3.cpp; sourceTree = ""; }; + F643F2402829B4D0000B8B40 /* Sphere1.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Sphere1.h; sourceTree = ""; }; + F643F2412829B5BD000B8B40 /* Segment1.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Segment1.hpp; sourceTree = ""; }; + F643F2422829B5E7000B8B40 /* Segment1.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = Segment1.inl; sourceTree = ""; }; + F643F2432829CD92000B8B40 /* Vector2.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Vector2.h; sourceTree = ""; }; + F646BFB12AF1934D007D898C /* FloatPack.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = FloatPack.inl; sourceTree = ""; }; + F646BFB22AF19E1A007D898C /* FloatPack.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = FloatPack.cpp; sourceTree = ""; }; + F646BFB52AF1A018007D898C /* libCore_Zero.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libCore_Zero.a; sourceTree = BUILT_PRODUCTS_DIR; }; + F646BFB72AF1C6A7007D898C /* libCore_Misc.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libCore_Misc.a; sourceTree = BUILT_PRODUCTS_DIR; }; + F66D9E1329314330009D7D3D /* SimpleLine.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SimpleLine.cpp; sourceTree = ""; }; + F68079562A92AD1E008E6505 /* Box3.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Box3.h; sourceTree = ""; }; + F68079572A92AD33008E6505 /* Box3.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Box3.hpp; sourceTree = ""; }; + F687F4A129CB1AEC00BE1F70 /* Sphere3.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Sphere3.cpp; sourceTree = ""; }; + F6971DB2282ACDA5008FBD17 /* Segment1.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Segment1.h; sourceTree = ""; }; + F6971F50282B1229008FBD17 /* libCore_Math_iOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCore_Math_iOS.a; sourceTree = BUILT_PRODUCTS_DIR; }; + F69BE34A2B8C0199006C7BE2 /* _delete */ = {isa = PBXFileReference; lastKnownFileType = folder; path = _delete; sourceTree = ""; }; + F69BE34B2B8C01DE006C7BE2 /* Distance+BigInt.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Distance+BigInt.inl"; sourceTree = ""; }; + F69BE34C2B8C0207006C7BE2 /* Algorithm+Split+BigInt.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Algorithm+Split+BigInt.inl"; sourceTree = ""; }; + F69CC2552D2975C400FB29DE /* clamp.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = clamp.hpp; sourceTree = ""; }; + F6A293882D33138000222CB6 /* Eulers.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Eulers.hpp; sourceTree = ""; }; + F6A293892D3313C000222CB6 /* Eulers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Eulers.h; sourceTree = ""; }; + F6BF9BE72E390240002E6AF0 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; + F6C3283A282DA2D200DF0950 /* Vector4.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = Vector4.inl; sourceTree = ""; }; + F6C3283B282DA2D200DF0950 /* Vector4.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Vector4.h; sourceTree = ""; }; + F6C3283C282DA2D200DF0950 /* Vector4.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Vector4.hpp; sourceTree = ""; }; + F6C48C7D28B0204E007327B4 /* SimpleLine.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SimpleLine.h; sourceTree = ""; }; + F6C48C7E28B0206F007327B4 /* SimpleLine.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = SimpleLine.hpp; sourceTree = ""; }; + F6D878DD285BD3ED001B6C6D /* Precision.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Precision.h; sourceTree = ""; }; + F6E526632884A0B6003BB6F1 /* mean.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = mean.hpp; sourceTree = ""; }; + F6E526642884D4AF003BB6F1 /* Distance.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = Distance.inl; sourceTree = ""; }; + F6EA13D0285B786000171F82 /* Accuracy+IO.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Accuracy+IO.h"; sourceTree = ""; }; + F6EA13D1285B79D600171F82 /* Accuracy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Accuracy.h; sourceTree = ""; }; + F6EA13D2285B88C900171F82 /* RelativeFront.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RelativeFront.h; sourceTree = ""; }; + F6EA13D3285B88C900171F82 /* RelativeFront+IO.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RelativeFront+IO.h"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + F608A99A2826B7C8005C276B /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F608AAA028270475005C276B /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + F646BFB82AF1C6A8007D898C /* libCore_Misc.a in Frameworks */, + F646BFB62AF1A018007D898C /* libCore_Zero.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F6971F4C282B1229008FBD17 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + F608A9932826B7C8005C276B = { + isa = PBXGroup; + children = ( + F646BFB42AF1A018007D898C /* Frameworks */, + F6BF9BE72E390240002E6AF0 /* Makefile */, + F608AB6B2827F3C5005C276B /* Makefile.def */, + F608AB6C2827F3C5005C276B /* Makefile.project */, + F608A99D2826B7C8005C276B /* Products */, + F608AAA428270475005C276B /* tests */, + F61D7C442E3816A0002A1AED /* tjp */, + ); + sourceTree = ""; + }; + F608A99D2826B7C8005C276B /* Products */ = { + isa = PBXGroup; + children = ( + F608A99C2826B7C8005C276B /* libCore_Math.a */, + F608AAA328270475005C276B /* Core_Math_Tests */, + F6971F50282B1229008FBD17 /* libCore_Math_iOS.a */, + ); + name = Products; + sourceTree = ""; + }; + F608A9B42826BA86005C276B /* core */ = { + isa = PBXGroup; + children = ( + F608AA3D2826BCCE005C276B /* math */, + ); + path = core; + sourceTree = ""; + }; + F608AA3D2826BCCE005C276B /* math */ = { + isa = PBXGroup; + children = ( + F61F9BF62C6E507300F79137 /* _tests */, + F69BE34A2B8C0199006C7BE2 /* _delete */, + F6EA13D1285B79D600171F82 /* Accuracy.h */, + F6EA13D0285B786000171F82 /* Accuracy+IO.h */, + F608AA5C2826BCCE005C276B /* Algorithm.cpp */, + F608AA472826BCCE005C276B /* Algorithm.h */, + F608AA4C2826BCCE005C276B /* Algorithm.hpp */, + F608AA412826BCCE005C276B /* Algorithm.inl */, + F608AA4F2826BCCE005C276B /* Algorithm+Segment.cpp */, + F608AA5F2826BCCE005C276B /* Algorithm+Segment.hpp */, + F608AA622826BCCE005C276B /* Algorithm+Segment.inl */, + F608AA5E2826BCCE005C276B /* Algorithm+SimplifyCurve.cpp */, + F608AA4D2826BCCE005C276B /* Algorithm+SimplifyCurve.hpp */, + F608AA642826BCCE005C276B /* Algorithm+Split.cpp */, + F608AA3E2826BCCE005C276B /* Algorithm+Split.hpp */, + F608AA4E2826BCCE005C276B /* Algorithm+Split.inl */, + F69BE34C2B8C0207006C7BE2 /* Algorithm+Split+BigInt.inl */, + F608AA562826BCCE005C276B /* detail */, + F6E526642884D4AF003BB6F1 /* Distance.inl */, + F69CC2552D2975C400FB29DE /* clamp.hpp */, + F69BE34B2B8C01DE006C7BE2 /* Distance+BigInt.inl */, + F608AA552826BCCE005C276B /* Epsilon.h */, + F608AA4A2826BCCE005C276B /* FastFourier.h */, + F608AA462826BCCE005C276B /* GTE_convert.hpp */, + F643F23C2829B3C3000B8B40 /* HMatrix.cpp */, + F643F23A2829B216000B8B40 /* HMatrix.h */, + F643F2392829B1DE000B8B40 /* HMatrix.hpp */, + F643F23B2829B23C000B8B40 /* HMatrix.inl */, + F643F22E2829AC00000B8B40 /* HPoint.h */, + F643F22C2829AAF2000B8B40 /* HPoint.hpp */, + F643F22D2829AB76000B8B40 /* HPoint.inl */, + F608AA612826BCCE005C276B /* Math.h */, + F608AA532826BCCE005C276B /* Math.hpp */, + F608AA682826BCCE005C276B /* Math.inl */, + F608AA442826BCCE005C276B /* Math+IO.h */, + F608ABC828287338005C276B /* Math+V.h */, + F608AA5A2826BCCE005C276B /* MathGlmC.h */, + F643F23D2829B3C4000B8B40 /* Matrix3.cpp */, + F643F2332829B01F000B8B40 /* Matrix3.h */, + F643F2312829AF0B000B8B40 /* Matrix3.hpp */, + F643F2322829AF5C000B8B40 /* Matrix3.inl */, + F6E526632884A0B6003BB6F1 /* mean.hpp */, + F6D878DD285BD3ED001B6C6D /* Precision.h */, + F608AA542826BCCE005C276B /* Real.cpp */, + F608AA502826BCCE005C276B /* Real.h */, + F608ABA7282865E8005C276B /* Real.hpp */, + F608AA452826BCCE005C276B /* Real.inl */, + F646BFB12AF1934D007D898C /* FloatPack.inl */, + F6EA13D2285B88C900171F82 /* RelativeFront.h */, + F6EA13D3285B88C900171F82 /* RelativeFront+IO.h */, + F6971DB2282ACDA5008FBD17 /* Segment1.h */, + F643F2412829B5BD000B8B40 /* Segment1.hpp */, + F643F2422829B5E7000B8B40 /* Segment1.inl */, + F6C48C7D28B0204E007327B4 /* SimpleLine.h */, + F6C48C7E28B0206F007327B4 /* SimpleLine.hpp */, + F66D9E1329314330009D7D3D /* SimpleLine.cpp */, + F643F2402829B4D0000B8B40 /* Sphere1.h */, + F643F2352829B086000B8B40 /* Sphere1.hpp */, + F643F2382829B179000B8B40 /* Sphere1.inl */, + F643F2372829B135000B8B40 /* Sphere3.h */, + F68079562A92AD1E008E6505 /* Box3.h */, + F68079572A92AD33008E6505 /* Box3.hpp */, + F643F2342829B054000B8B40 /* Sphere3.hpp */, + F687F4A129CB1AEC00BE1F70 /* Sphere3.cpp */, + F643F2362829B0DD000B8B40 /* Sphere3.inl */, + F608AA5D2826BCCE005C276B /* Statistics.h */, + F643F2432829CD92000B8B40 /* Vector2.h */, + F643F22F2829AD00000B8B40 /* Vector2.hpp */, + F643F2302829AD31000B8B40 /* Vector2.inl */, + F643F22B2829AA66000B8B40 /* Vector3.h */, + F643F2292829A919000B8B40 /* Vector3.hpp */, + F6A293882D33138000222CB6 /* Eulers.hpp */, + F6A293892D3313C000222CB6 /* Eulers.h */, + F643F22A2829A9A2000B8B40 /* Vector3.inl */, + F6C3283B282DA2D200DF0950 /* Vector4.h */, + F6C3283C282DA2D200DF0950 /* Vector4.hpp */, + F6C3283A282DA2D200DF0950 /* Vector4.inl */, + F608AA662826BCCE005C276B /* Zero.h */, + ); + path = math; + sourceTree = ""; + }; + F608AA562826BCCE005C276B /* detail */ = { + isa = PBXGroup; + children = ( + F608AA572826BCCE005C276B /* Wm5.h */, + F608AA582826BCCE005C276B /* Wm5.inl */, + F608AA592826BCCE005C276B /* Wm5.cpp */, + ); + path = detail; + sourceTree = ""; + }; + F608AAA428270475005C276B /* tests */ = { + isa = PBXGroup; + children = ( + F61F9BF52C6E506000F79137 /* Makefile.project */, + F608AAA528270475005C276B /* main.cpp */, + ); + path = tests; + sourceTree = ""; + }; + F61D7C442E3816A0002A1AED /* tjp */ = { + isa = PBXGroup; + children = ( + F608A9B42826BA86005C276B /* core */, + ); + path = tjp; + sourceTree = ""; + }; + F61F9BF62C6E507300F79137 /* _tests */ = { + isa = PBXGroup; + children = ( + F608AA4B2826BCCE005C276B /* Algorithm.cpp */, + F646BFB22AF19E1A007D898C /* FloatPack.cpp */, + F608AA512826BCCE005C276B /* Algorithm+Segment.cpp */, + ); + path = _tests; + sourceTree = ""; + }; + F646BFB42AF1A018007D898C /* Frameworks */ = { + isa = PBXGroup; + children = ( + F646BFB72AF1C6A7007D898C /* libCore_Misc.a */, + F646BFB52AF1A018007D898C /* libCore_Zero.a */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + F608A9982826B7C8005C276B /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + F608AB02282726A5005C276B /* Algorithm+Segment.hpp in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F6971F3E282B1229008FBD17 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + F6971F3F282B1229008FBD17 /* Algorithm+Segment.hpp in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + F608A99B2826B7C8005C276B /* Core_Math */ = { + isa = PBXNativeTarget; + buildConfigurationList = F608A9A02826B7C8005C276B /* Build configuration list for PBXNativeTarget "Core_Math" */; + buildPhases = ( + F608A9982826B7C8005C276B /* Headers */, + F608A9992826B7C8005C276B /* Sources */, + F608A99A2826B7C8005C276B /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Core_Math; + productName = Core_Math; + productReference = F608A99C2826B7C8005C276B /* libCore_Math.a */; + productType = "com.apple.product-type.library.static"; + }; + F608AAA228270475005C276B /* Core_Math_Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = F608AAA728270475005C276B /* Build configuration list for PBXNativeTarget "Core_Math_Tests" */; + buildPhases = ( + F608AA9F28270475005C276B /* Sources */, + F608AAA028270475005C276B /* Frameworks */, + F608AAA128270475005C276B /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Core_Math_Tests; + productName = Core_Math_Tests; + productReference = F608AAA328270475005C276B /* Core_Math_Tests */; + productType = "com.apple.product-type.tool"; + }; + F6971F3D282B1229008FBD17 /* Core_Math_iOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = F6971F4D282B1229008FBD17 /* Build configuration list for PBXNativeTarget "Core_Math_iOS" */; + buildPhases = ( + F6971F3E282B1229008FBD17 /* Headers */, + F6971F40282B1229008FBD17 /* Sources */, + F6971F4C282B1229008FBD17 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Core_Math_iOS; + productName = Core_Math; + productReference = F6971F50282B1229008FBD17 /* libCore_Math_iOS.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + F608A9942826B7C8005C276B /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + DefaultBuildSystemTypeForWorkspace = Original; + LastUpgradeCheck = 1330; + TargetAttributes = { + F608A99B2826B7C8005C276B = { + CreatedOnToolsVersion = 13.3; + }; + F608AAA228270475005C276B = { + CreatedOnToolsVersion = 13.3; + }; + }; + }; + buildConfigurationList = F608A9972826B7C8005C276B /* Build configuration list for PBXProject "Core_Math" */; + compatibilityVersion = "Xcode 13.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = F608A9932826B7C8005C276B; + productRefGroup = F608A99D2826B7C8005C276B /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + F608A99B2826B7C8005C276B /* Core_Math */, + F6971F3D282B1229008FBD17 /* Core_Math_iOS */, + F608AAA228270475005C276B /* Core_Math_Tests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + F608A9992826B7C8005C276B /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F608AB03282726AA005C276B /* Algorithm+SimplifyCurve.cpp in Sources */, + F687F4A229CB1AFC00BE1F70 /* Sphere3.cpp in Sources */, + F608AB04282726AD005C276B /* Algorithm.cpp in Sources */, + F643F23E2829B3FB000B8B40 /* HMatrix.cpp in Sources */, + F643F23F2829B3FE000B8B40 /* Matrix3.cpp in Sources */, + F608AAFD2827266A005C276B /* Algorithm+Split.cpp in Sources */, + F69548A528288DF3005D1B64 /* Real.cpp in Sources */, + F608AB06282726B7005C276B /* Algorithm+Segment.cpp in Sources */, + F66D9E1429314376009D7D3D /* SimpleLine.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F608AA9F28270475005C276B /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F646BFB32AF19E22007D898C /* FloatPack.cpp in Sources */, + F608AAA628270475005C276B /* main.cpp in Sources */, + F608AB07282726BC005C276B /* Algorithm.cpp in Sources */, + F608AB05282726B2005C276B /* Algorithm+Segment.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F6971F40282B1229008FBD17 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F6971F41282B1229008FBD17 /* Algorithm+SimplifyCurve.cpp in Sources */, + F687F4A329CB1AFD00BE1F70 /* Sphere3.cpp in Sources */, + F6971F42282B1229008FBD17 /* Algorithm.cpp in Sources */, + F6971F44282B1229008FBD17 /* HMatrix.cpp in Sources */, + F6971F45282B1229008FBD17 /* Matrix3.cpp in Sources */, + F6971F47282B1229008FBD17 /* Algorithm+Split.cpp in Sources */, + F6971F48282B1229008FBD17 /* Real.cpp in Sources */, + F6971F49282B1229008FBD17 /* Algorithm+Segment.cpp in Sources */, + F66D9E1529314377009D7D3D /* SimpleLine.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + F608A99E2826B7C8005C276B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + ../Core_Zero, + ../Core_IO, + ../Core_Misc, + ); + IPHONEOS_DEPLOYMENT_TARGET = 13.6; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + F608A99F2826B7C8005C276B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + ../Core_Zero, + ../Core_IO, + ../Core_Misc, + ); + IPHONEOS_DEPLOYMENT_TARGET = 13.6; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = macosx; + }; + name = Release; + }; + F608A9A12826B7C8005C276B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = T2M28D3T75; + EXECUTABLE_PREFIX = lib; + HEADER_SEARCH_PATHS = ( + ../Core_Zero, + ../Core_IO, + ../Libraries/sdk/Darwin/include, + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + F608A9A22826B7C8005C276B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = T2M28D3T75; + EXECUTABLE_PREFIX = lib; + HEADER_SEARCH_PATHS = ( + ../Core_Zero, + ../Core_IO, + ../Libraries/sdk/Darwin/include, + ); + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; + F608AAA828270475005C276B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = T2M28D3T75; + ENABLE_HARDENED_RUNTIME = YES; + HEADER_SEARCH_PATHS = ( + "${inherited}", + ../Core_Math, + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + F608AAA928270475005C276B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = T2M28D3T75; + ENABLE_HARDENED_RUNTIME = YES; + HEADER_SEARCH_PATHS = ( + "${inherited}", + ../Core_Math, + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + F6971F4E282B1229008FBD17 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = T2M28D3T75; + EXECUTABLE_PREFIX = lib; + HEADER_SEARCH_PATHS = ( + ../Core_Zero, + ../Core_IO, + ../Libraries/sdk/include, + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + F6971F4F282B1229008FBD17 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = T2M28D3T75; + EXECUTABLE_PREFIX = lib; + HEADER_SEARCH_PATHS = ( + ../Core_Zero, + ../Core_IO, + ../Libraries/sdk/include, + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + F608A9972826B7C8005C276B /* Build configuration list for PBXProject "Core_Math" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F608A99E2826B7C8005C276B /* Debug */, + F608A99F2826B7C8005C276B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F608A9A02826B7C8005C276B /* Build configuration list for PBXNativeTarget "Core_Math" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F608A9A12826B7C8005C276B /* Debug */, + F608A9A22826B7C8005C276B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F608AAA728270475005C276B /* Build configuration list for PBXNativeTarget "Core_Math_Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F608AAA828270475005C276B /* Debug */, + F608AAA928270475005C276B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F6971F4D282B1229008FBD17 /* Build configuration list for PBXNativeTarget "Core_Math_iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F6971F4E282B1229008FBD17 /* Debug */, + F6971F4F282B1229008FBD17 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = F608A9942826B7C8005C276B /* Project object */; +} diff --git a/Core_Math.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Core_Math.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/Core_Math.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Core_Math.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Core_Math.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Core_Math.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Core_Math.xcodeproj/xcshareddata/xcschemes/Core_Math_Tests.xcscheme b/Core_Math.xcodeproj/xcshareddata/xcschemes/Core_Math_Tests.xcscheme new file mode 100644 index 0000000..e7705fe --- /dev/null +++ b/Core_Math.xcodeproj/xcshareddata/xcschemes/Core_Math_Tests.xcscheme @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f61a565 --- /dev/null +++ b/Makefile @@ -0,0 +1,2 @@ +ROOTDIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST)))..) +include $(ROOTDIR)/Core_Make/tjp/Make/Makefile diff --git a/Makefile.def b/Makefile.def new file mode 100755 index 0000000..1e7b149 --- /dev/null +++ b/Makefile.def @@ -0,0 +1,6 @@ +timprepscius.core.include := $(timprepscius.core.include) -I $(dir $(realpath $(lastword $(MAKEFILE_LIST)))) +timprepscius.core.link := $(timprepscius.core.link) -L $(dir $(realpath $(lastword $(MAKEFILE_LIST))))/.bin/$(OBJDIR) + +timprepscius.core_math.include := -I $(dir $(realpath $(lastword $(MAKEFILE_LIST)))) +timprepscius.core_math.link := -L $(dir $(realpath $(lastword $(MAKEFILE_LIST))))/.bin/$(OBJDIR) + diff --git a/Makefile.project b/Makefile.project new file mode 100755 index 0000000..60ac3ba --- /dev/null +++ b/Makefile.project @@ -0,0 +1,19 @@ +include $(MAKEDIR)/Makefile.base + +# use: ls -d tjp/core/*/ tjp/core/*/*/ | rev | cut -c 2- | rev | sed 's/$/ \\/' + +PROJECTS := \ + tjp/core/math \ + tjp/core/math/detail \ + +#SRC_PCH := tjp/core/Precompile.pch + +INCPATH := \ + $(timprepscius.libraries.cpp.include) \ + $(timprepscius.core.include) + +LIBFILE := libCore_Math.a + +COPYTO := $(LIBRARIES_PROJECT) + +include $(MAKEDIR)/Makefile.lib diff --git a/tests/Makefile b/tests/Makefile new file mode 120000 index 0000000..b8f87c1 --- /dev/null +++ b/tests/Makefile @@ -0,0 +1 @@ +../../Make/Makefile \ No newline at end of file diff --git a/tests/Makefile.project b/tests/Makefile.project new file mode 100755 index 0000000..363e96e --- /dev/null +++ b/tests/Makefile.project @@ -0,0 +1,32 @@ +include $(MAKEDIR)/Makefile.base + +# use: ls -d core/*/ core/*/*/ | rev | cut -c 2- | rev | sed 's/$/ \\/' + +PROJECTS := \ + . \ + ../core/math/_tests \ + + +INCPATH := \ + $(timprepscius.libraries.cpp.include) \ + $(timprepscius.core.include) + +LDPATH := $(timprepscius.libraries.cpp.link) + +LIBS := \ + -lCore_Zero \ + -lCore_Misc \ + -lCore_IO \ + -lCore_Allocator \ + -lz_ + +EXEFILE := Core_Math_Tests.exe + +#COPYTO := $(ROOTDIR)/.bin + +ifeq (Darwin,$(SYS_NAME)) + LIBS += -lc++ +endif + + +include $(MAKEDIR)/Makefile.bin diff --git a/tests/main.cpp b/tests/main.cpp new file mode 100644 index 0000000..ce9ef54 --- /dev/null +++ b/tests/main.cpp @@ -0,0 +1,17 @@ +#define CATCH_CONFIG_RUNNER +#include + +#include + +using namespace tjp; +using namespace core; + +int main( int argc, char* argv[] ) +{ + xLogInitialize("Core_IO_Tests.txt"); + xLogActivateStory("testing"); + xLogActivateStory("debug"); + + int result = Catch::Session().run( argc, argv ); + return result; +} diff --git a/tjp/core/math/Accuracy+IO.h b/tjp/core/math/Accuracy+IO.h new file mode 100644 index 0000000..dc29141 --- /dev/null +++ b/tjp/core/math/Accuracy+IO.h @@ -0,0 +1,83 @@ +// +// MathIO.h +// common +// +// Created by Timothy Prepscius on 8/4/18. +// Copyright © 2018 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Math.h" +#include "Accuracy.h" +#include + +#include "Vector3.hpp" +#include "Sphere3.hpp" + +#include + +namespace tjp { +namespace core { +namespace math { + +template +void io_r(IO &io, DispatchIO &a) +{ + s64 v; + io.any(v); + *a.t->v = a.t->m * v; +} + +template +void io_w(IO &io, const DispatchIO &a) +{ + s64 v = std::round(*a.t->v / a.t->m); + io.any(v); +} + +template +void io_(IO &io, Accuracy &a) +{ + auto a_ = makeDispatchIO(a); + io.any(a_); +} + +template +void io_(IO &io, Accuracy> &a) +{ + auto &v = *a.v; + + io.array( + with_accuracy(v[0], a.m), + with_accuracy(v[1], a.m), + with_accuracy(v[2], a.m) + ); +} + +template +void io_(IO &io, Accuracy> &a) +{ + auto &v = *a.v; + + io.array( + with_accuracy(v[0], a.m), + with_accuracy(v[1], a.m) + ); +} + +template +void io_(IO &io, Accuracy> &a) +{ + auto &v = *a.v; + + io.object( + "center", with_accuracy(v.center, a.m), + "radius", with_accuracy(v.radius, a.m) + ); +} + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Accuracy.h b/tjp/core/math/Accuracy.h new file mode 100644 index 0000000..bf0ad5f --- /dev/null +++ b/tjp/core/math/Accuracy.h @@ -0,0 +1,50 @@ +// +// MathIO.h +// common +// +// Created by Timothy Prepscius on 8/4/18. +// Copyright © 2018 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Real.h" + + +namespace tjp { +namespace core { +namespace math { + +template +struct Accuracy +{ + V *v; + Real m; +} ; + +template +Accuracy with_accuracy(V &v, Real m) +{ + return Accuracy { &v, m }; +} + +constexpr s64 compile_time_pow10(const int digits) +{ + if (digits == 0) + return 1; + + return 10 * compile_time_pow10(digits-1); +} + +constexpr Real accuracy_with_digits(const int digits) +{ + if (digits < 0) + return 1.0 / compile_time_pow10(-digits); + + return compile_time_pow10(digits); +} + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Algorithm+Segment.cpp b/tjp/core/math/Algorithm+Segment.cpp new file mode 100755 index 0000000..9422f9f --- /dev/null +++ b/tjp/core/math/Algorithm+Segment.cpp @@ -0,0 +1,71 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#include "Algorithm+Segment.hpp" +#include "Math.hpp" + +namespace tjp { +namespace core { +namespace math { + +template<> +std::tuple, math::Segment1> bisectingSegments(const std::vector> &v) +{ + typedef s64 Real; + + Real mean = 0; + int count = 0; + Real l, r; + + bool first = true; + for (auto &s: v) + { + auto [l0, r0] = sortedSegment(s); + +// auto numPoints = 10; +// auto d0 = r0 - l0; +// for (auto i=0; i r) + r = r0; + } + } + + if (count > 0) + mean = mean / count; + +// auto middle = (l + r) / 2; +// auto middle = l + (r - l) / 2; + + auto ls = math::Segment1 { l, mean }; + auto rs = math::Segment1 { mean, r }; + return { ls, rs }; +} + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Algorithm+Segment.hpp b/tjp/core/math/Algorithm+Segment.hpp new file mode 100755 index 0000000..0ed8168 --- /dev/null +++ b/tjp/core/math/Algorithm+Segment.hpp @@ -0,0 +1,22 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Algorithm.h" + +namespace tjp { +namespace core { +namespace math { + + +} // namespace +} // namespace +} // namespace + +#include "Algorithm+Segment.inl" diff --git a/tjp/core/math/Algorithm+Segment.inl b/tjp/core/math/Algorithm+Segment.inl new file mode 100755 index 0000000..a3528f8 --- /dev/null +++ b/tjp/core/math/Algorithm+Segment.inl @@ -0,0 +1,225 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Algorithm.h" +#include "Math.hpp" +#include "Zero.h" +#include "Segment1.hpp" + + +namespace tjp { +namespace core { +namespace math { + + +template +std::tuple sortedSegment(const Segment1 &segment) +{ + if (segment.begin < segment.end) + { + return { segment.begin, segment.end }; + } + + return { segment.end, segment.begin }; +} + +template +bool intersects_segment (const S &l, const S &r, R error) +{ + /* + abs((l.l+l.r)/2 - (r.l+r.r))/2 <= abs(l.r-l.l)/2 + abs(r.r-r.l)/2 + error + + abs( (l.l+l.r) - (r.l+r.r) )/2 <= (abs(l.r-l.l) + abs(r.r-r.l)) / 2 + abs( (l.l+l.r) + (r.l+r.r) ) <= 2 * abs(l.r-l.l) + abs(r.r-r.l) + 2*error + + */ + +// return distance((l.begin+l.end),(r.begin+r.end)) <= length(l) + length(r) + 2*error; + + auto [l0,r0] = sortedSegment(l); + auto [l1,r1] = sortedSegment(r); + + if (l1 <= l0+error && r1 >= r0-error) + return true; + + if (l1 >= l0-error && l1 <= r0+error) + return true; + + if (r1 >= l0-error && r1 <= r0+error) + return true; + + return false; +} +template +bool intersects_segment (const S &l, const S &r) +{ + /* + abs((l.l+l.r)/2 - (r.l+r.r))/2 <= abs(l.r-l.l)/2 + abs(r.r-r.l)/2 + error + + abs( (l.l+l.r) - (r.l+r.r) )/2 <= (abs(l.r-l.l) + abs(r.r-r.l)) / 2 + abs( (l.l+l.r) + (r.l+r.r) ) <= 2 * abs(l.r-l.l) + abs(r.r-r.l) + 2*error + + */ + +// return distance((l.begin+l.end),(r.begin+r.end)) <= length(l) + length(r) + 2*error; + + auto [l0,r0] = sortedSegment(l); + auto [l1,r1] = sortedSegment(r); + + if (l1 <= l0 && r1 >= r0) + return true; + + if (l1 >= l0 && l1 <= r0) + return true; + + if (r1 >= l0 && r1 <= r0) + return true; + + return false; +} + +template +bool intersects(const Segment1 &s0, const Segment1 &s1, const Real &error) +{ + return intersects_segment(s0, s1, error); +} + +template +bool intersects(const Segment1 &s0, const Segment1 &s1) +{ + return intersects_segment(s0, s1); +} + +template +Real distance(const Segment1 &segment, const Real &p) +{ + auto [l, r] = sortedSegment(segment); + + if (p <= l) + return l - p; + if (p >= r) + return p - r; + + return -std::min(distance(p,l), distance(p,r)); +} + +template +bool intersects_segment_point (const S &s, const R &p, R error) +{ + auto [l, r] = sortedSegment(s); + return (l <= p) && (p <= r); +} + +template +bool contains_segment (const S &l, const S &r) +{ + auto [l0,r0] = sortedSegment(l); + auto [l1,r1] = sortedSegment(r); + + if (l0 <= l1 && r0 >= r1) + return true; + + return false; +} + +template +bool contains_segment (const S &l, const S &r, R error) +{ + auto [l0,r0] = sortedSegment(l); + auto [l1,r1] = sortedSegment(r); + + if (l0 <= l1+error && r0 >= r1-error) + return true; + + return false; +} + + +template +bool contains (const math::Segment1 &l, const math::Segment1 &r) +{ + return contains_segment(l, r); +} + +template +bool contains (const math::Segment1 &l, const math::Segment1 &r, Real error) +{ + return contains_segment(l, r, error); +} + +template +std::tuple, math::Segment1> bisectingSegments(const std::vector> &v) +{ + Real l, r; + bool first = true; + for (auto &s: v) + { + auto [l0, r0] = sortedSegment(s); + if (first) + { + first = false; + l = l0; + r = r0; + } + else + { + if (l0 < l) + l = l0; + if (r0 > r) + r = r0; + } + } + + auto middle = (l + r) / 2; +// auto middle = l + (r - l) / 2; + + auto ls = math::Segment1 { l, middle }; + auto rs = math::Segment1 { middle, r }; + return { ls, rs }; +} + +template<> +std::tuple, math::Segment1> bisectingSegments(const std::vector> &v); + + +template +math::Segment1 segmentContaining(const std::vector> &v, const math::Segment1 &zero) +{ + if (v.empty()) + return zero; + + Real l, r; + bool first = true; + for (auto &s: v) + { + auto [l0, r0] = sortedSegment(s); + if (first) + { + first = false; + l = l0; + r = r0; + } + else + { + if (l0 < l) + l = l0; + if (r0 > r) + r = r0; + } + } + + auto s = math::Segment1 { l, r }; + return s; +} + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Algorithm+SimplifyCurve.cpp b/tjp/core/math/Algorithm+SimplifyCurve.cpp new file mode 100755 index 0000000..59e6131 --- /dev/null +++ b/tjp/core/math/Algorithm+SimplifyCurve.cpp @@ -0,0 +1,102 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#include "Algorithm+SimplifyCurve.hpp" + +#include "Math.hpp" +#include "Algorithm.hpp" + +namespace tjp { +namespace core { +namespace math { + +typedef math::Vector3r SimplifyVertex; +typedef core::MemoryArray SimplifyPoints; + +// read this and made this, not sure if the same +// https://towardsdatascience.com/simplify-polylines-with-the-douglas-peucker-algorithm-ac8ed487a4a1 + +typedef std::vector SimplifyResult; + +void simplify(SimplifyResult &result, const SimplifyPoints &points, size_t from, size_t to, size_t iterations) +{ + if (to == from) + return; + + Segment3 segment { points[from], points[to] }; + + size_t farthest = 0; + Real farthestDistance = 0; + + for (auto i = from+1; i!=to; ++i) + { + auto distance = math::distance(segment, points[i]); + if (!farthest || distance > farthestDistance) + { + farthest = i; + farthestDistance = distance; + } + } + + if (farthest && iterations > 0) + { + simplify(result, points, from , farthest, iterations-1); + simplify(result, points, farthest, to, iterations-1); + } + else + { + if (farthest) + result.push_back(farthest); + + result.push_back(to); + } +} + +SimplifyResult simplify(const SimplifyPoints &points, size_t iterations) +{ + if (points.size() < 2) + return SimplifyResult {}; + + size_t farthest = 0; + auto begin = 0; + auto end = points.size()-1; + Real farthestDistance = 0; + + SimplifyResult result; + result.push_back(begin); + + if (points.front() == points.back()) + { + for (auto to=1; to!=end; ++to) + { + auto distance = math::distance(points[begin], points[to]); + if (!farthest || distance > farthestDistance) + { + farthest = to; + farthestDistance = distance; + } + } + + simplify(result, points, begin, farthest, iterations-1); + + if (farthest != end) + simplify(result, points, farthest, end, iterations-1); + } + else + { + simplify(result, points, begin, end, iterations); + } + + return result; +} + + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Algorithm+SimplifyCurve.hpp b/tjp/core/math/Algorithm+SimplifyCurve.hpp new file mode 100755 index 0000000..b2de065 --- /dev/null +++ b/tjp/core/math/Algorithm+SimplifyCurve.hpp @@ -0,0 +1,49 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Algorithm.h" +#include + +namespace tjp { +namespace core { +namespace math { + +std::vector simplify(const core::MemoryArray &points, size_t iterations); + +template +std::vector simplify(const T &points_, size_t iterations, F &&f) +{ + std::vector points; + for (auto &v: points_) + { + points.push_back(f(v)); + } + + return simplify(points, iterations); +} + +template +T simplified(const T &t, const std::vector &indices) +{ + T result; + result.reserve(indices.size()); + for (auto &i : indices) + { + result.push_back(t[i]); + } + + return result; +} + + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Algorithm+Split+BigInt.inl b/tjp/core/math/Algorithm+Split+BigInt.inl new file mode 100755 index 0000000..1c58c40 --- /dev/null +++ b/tjp/core/math/Algorithm+Split+BigInt.inl @@ -0,0 +1,197 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Algorithm+Split.hpp" +#include "Algorithm.inl" +#include "Math.hpp" +#include "BigInt.h" +#include "BigDecimal.h" + +#include +#include + +namespace tjp { +namespace core { +namespace math { + +template +Sphere1 sphereContaining_points(I i, I end, const Sphere1 &emptyValue) +{ + if (i == end) + return emptyValue; + + auto &s = *i; + auto l = s; + auto r = s; + + sLogDebug("sphereContaining_spheres", logVar(s)); + + for (++i; i != end; ++i) + { + auto &v = *i; + + l = min_value(l, v); + r = max_value(r, v); + + sLogDebug("sphereContaining_spheres", logVar(*i) << logVar(l) << logVar(r)); + } + + auto c = (l+r)/2; + auto rmc = distance(r,c); + auto cml = distance(c,l); + + sLogDebug("sphereContaining_spheres", logVar(c) << logVar(rmc) << logVar(cml)); + + auto radius = max_value(rmc, cml); + + sLogDebug("sphereContaining_spheres", logVar(c) << logVar(radius)); + + return { c, radius }; +} + +template +std::tuple, math::Sphere1> bisectingRegions(const std::vector &translates_) +{ + debug_assert(!translates_.empty()); + debug_assert(translates_.size() > 1); + + auto sortable = translates_; + std::sort(sortable.begin(), sortable.end()); + + auto begin = sortable.begin(); + auto halfL = begin + sortable.size()/2; + auto halfR = halfL + 1; + auto end = sortable.end(); + + auto l = sphereContaining_points(begin, halfR, Sphere1::Zero); + auto r = sphereContaining_points(halfR, end, Sphere1::Zero); + +#ifdef _DEBUG + for (auto i=begin; i != halfR; ++i) + { + if (!intersects(l, *i))// || intersects(r, *i)) + { + for (auto i=begin; i!=halfR; ++i) + { + sLogDebug("debug", "L " << logVar(*i)); + } + + for (auto i=halfR; i!=end; ++i) + { + sLogDebug("debug", "R " << logVar(*i)); + } + + sLogDebug("debug", logVar(l) << logVar(r) << logVar(*i) << logVar(distance(l.center, *i))); + + { + auto sortable = translates_; + std::sort(sortable.begin(), sortable.end()); + + auto begin = sortable.begin(); + auto halfL = begin + sortable.size()/2; + auto halfR = halfL + 1; + auto l = sphereContaining_points(begin, halfR, Sphere1::Zero); + intersects(l, *i); + } + } + debug_assert(intersects(l, *i)); +// debug_assert(!intersects(r, *i)); + } + + for (auto i=halfR; i != end; ++i) + { + if (!intersects(r, *i)) + { + for (auto i=begin; i!=halfR; ++i) + { + sLogDebug("debug", "L " << logVar(*i)); + } + + for (auto i=halfR; i!=end; ++i) + { + sLogDebug("debug", "R " << logVar(*i)); + } + + sLogDebug("debug", logVar(l) << logVar(r) << logVar(*i) << logVar(distance(r.center, *i))); + auto r = sphereContaining_points(halfR, end, Sphere1::Zero); + intersects(r, *i); + } + + debug_assert(intersects(r, *i)); +// debug_assert(!intersects(l, *i)); + } +#endif + + return { l, r }; +} + +template +Sphere1 sphereContaining_spheres(I begin, I end, const Sphere1 &emptyValue) +{ + if (begin == end) + return emptyValue; + + auto c = begin->center; + + auto i=begin; + ++i; + + size_t count = 0; + for (;i!=end; ++i) + { + c = c + i->center; + count++; + } + + c = c / count; + auto radius = distance(begin->center, c) + begin->radius; + + i = begin; + ++i; + + for (;i!=end; ++i) + { + auto v = distance(i->center, c) + i->radius; + radius = max_value(radius, v); + } + + return { c, radius }; +} + +template +math::Sphere1 sphereContaining(const std::vector> &spheres, const math::Sphere1 &emptyValue) +{ + return sphereContaining_spheres(spheres.begin(), spheres.end(), emptyValue); +} + +template +math::Sphere3 sphereContaining(const math::Sphere3 &emptyValue, T &t, F &&f) +{ + std::vector> spheres; + for (auto &v : t) + spheres.push_back(f(v)); + + return sphereContaining(spheres, emptyValue); +} + +template +math::Sphere1 sphereContaining(const math::Sphere1 &emptyValue, T &t, F &&f) +{ + std::vector> spheres; + for (auto &v : t) + spheres.push_back(f(v)); + + return sphereContaining(spheres, emptyValue); +} + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Algorithm+Split.cpp b/tjp/core/math/Algorithm+Split.cpp new file mode 100755 index 0000000..bac42a2 --- /dev/null +++ b/tjp/core/math/Algorithm+Split.cpp @@ -0,0 +1,178 @@ +// +// Math.cpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#include "Algorithm+Split.hpp" +#include "Sphere3.hpp" + + +#include + +#define dynamic_cast static_cast +#define GTE_NO_LOGGER +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "GTE_convert.hpp" +#undef dynamic_cast + +#include +#include +#include + +namespace tjp { +namespace core { +namespace math { + +template +std::tuple, math::Sphere3> bisectingRegions_(const std::vector> &translates_) +{ + std::vector> translates; + + for (auto &p : translates_) + translates.push_back(gte_c(p)); + + gte::ApprOrthogonalLine3 orthogonalLineFit; + orthogonalLineFit.Fit((int)translates.size(), translates.data()); + auto &line = orthogonalLineFit.GetParameters(); + + std::vector> left, right; + for (auto &t : translates) + { + if (gte::Dot((t - line.origin), line.direction) > 0) + right.push_back(t); + else + left.push_back(t); + } + +// { +// auto mean = statistics::mean(left); +// auto stdev = statistics::stdev(left, mean); +// +// for (auto &t : left) +// { +// if (length(t - mean) < 2*stdev) +// culledLeft.push_back(t); +// } +// } +// { +// auto mean = statistics::mean(right); +// auto stdev = statistics::stdev(right, mean); +// +// vector culled; +// for (auto &t : right) +// { +// if (length(t - mean) < 2*stdev) +// culledRight.push_back(t); +// } +// } + + sLogRelease("wired::split", logVar(left.size()) << logVar(right.size())); + + // ensure there is data in both sets + if (left.empty()) + left = right; + + if (right.empty()) + right = left; + + gte::Sphere3 leftSphere; +// gte::MinimumVolumeSphere3 leftSphereMinimum; + gte::GetContainer(left, leftSphere); + + gte::Sphere3 rightSphere; +// gte::MinimumVolumeSphere3 rightSphereMinimum; + gte::GetContainer(right, rightSphere); + + return { gte_c(leftSphere), gte_c(rightSphere) }; +} + + +template<> +std::tuple, math::Sphere3> bisectingRegions(const std::vector> &points) +{ + return bisectingRegions_(points); +} + +template<> +std::tuple, math::Sphere3> bisectingRegions(const std::vector> &points) +{ + return bisectingRegions_(points); +} + +// --------------------------------- + +template +Sphere3 sphereContaining_(const std::vector> &points, const Sphere3 &emptyValue) +{ + if (points.empty()) + return emptyValue; + + std::vector> points_; + points_.reserve(points.size()); + for (auto &p: points) + points_.push_back(gte_c(p)); + + gte::Sphere3 sphere; + gte::GetContainer(points_, sphere); + + return gte_c(sphere); +} + +template<> +Sphere3 sphereContaining(const std::vector> &points, const Sphere3 &emptyValue) +{ + return sphereContaining_(points, emptyValue); +} + + +template +Sphere3 sphereContaining_(const std::vector> &spheres, const Sphere3 &emptyValue) +{ + if (spheres.empty()) + return emptyValue; + + auto sphere = gte_c(spheres.front()); + if (sphere.radius == Sphere3::Infinite.radius) + return Sphere3::Infinite; + + for (auto i=spheres.begin()+1; i!=spheres.end(); ++i) + { + if (i->radius == Sphere3::Infinite.radius) + return Sphere3::Infinite; + + gte::Sphere3 merge; + gte::MergeContainers(sphere, gte_c(*i), merge); + sphere = merge; + } + + return gte_c(sphere); +} + +template<> +Sphere3 sphereContaining(const std::vector> &spheres, const Sphere3 &emptyValue) +{ + return sphereContaining_(spheres, emptyValue); +} + +template<> +Sphere3 sphereContaining(const std::vector> &spheres, const Sphere3 &emptyValue) +{ + return sphereContaining_(spheres, emptyValue); +} + +} // namespace +} // namespace +} // namespace diff --git a/tjp/core/math/Algorithm+Split.hpp b/tjp/core/math/Algorithm+Split.hpp new file mode 100755 index 0000000..9190856 --- /dev/null +++ b/tjp/core/math/Algorithm+Split.hpp @@ -0,0 +1,34 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Algorithm.hpp" + +namespace tjp { +namespace core { +namespace math { + +template<> +std::tuple, math::Sphere3> bisectingRegions(const std::vector> &points); + +template<> +std::tuple, math::Sphere3> bisectingRegions(const std::vector> &points); + + +template<> +math::Sphere3 sphereContaining(const std::vector> &spheres, const math::Sphere3 &emptyValue); + +template<> +math::Sphere3 sphereContaining(const std::vector> &spheres, const math::Sphere3 &emptyValue); + +} // namespace +} // namespace +} // namespace + +#include "Algorithm+Split.inl" diff --git a/tjp/core/math/Algorithm+Split.inl b/tjp/core/math/Algorithm+Split.inl new file mode 100755 index 0000000..956f564 --- /dev/null +++ b/tjp/core/math/Algorithm+Split.inl @@ -0,0 +1,195 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Algorithm+Split.hpp" +#include "Algorithm.inl" +#include "Math.hpp" + +#include +#include + +namespace tjp { +namespace core { +namespace math { + +template +Sphere1 sphereContaining_points(I i, I end, const Sphere1 &emptyValue) +{ + if (i == end) + return emptyValue; + + auto &s = *i; + auto l = s; + auto r = s; + + sLogDebug("sphereContaining_spheres", logVar(s)); + + for (++i; i != end; ++i) + { + auto &v = *i; + + l = min_value(l, v); + r = max_value(r, v); + + sLogDebug("sphereContaining_spheres", logVar(*i) << logVar(l) << logVar(r)); + } + + auto c = (l+r)/2; + auto rmc = distance(r,c); + auto cml = distance(c,l); + + sLogDebug("sphereContaining_spheres", logVar(c) << logVar(rmc) << logVar(cml)); + + auto radius = max_value(rmc, cml); + + sLogDebug("sphereContaining_spheres", logVar(c) << logVar(radius)); + + return { c, radius }; +} + +template +std::tuple, math::Sphere1> bisectingRegions(const std::vector &translates_) +{ + debug_assert(!translates_.empty()); + debug_assert(translates_.size() > 1); + + auto sortable = translates_; + std::sort(sortable.begin(), sortable.end()); + + auto begin = sortable.begin(); + auto halfL = begin + sortable.size()/2; + auto halfR = halfL + 1; + auto end = sortable.end(); + + auto l = sphereContaining_points(begin, halfR, Sphere1::Zero); + auto r = sphereContaining_points(halfR, end, Sphere1::Zero); + +#ifdef _DEBUG + for (auto i=begin; i != halfR; ++i) + { + if (!intersects(l, *i))// || intersects(r, *i)) + { + for (auto i=begin; i!=halfR; ++i) + { + sLogDebug("debug", "L " << logVar(*i)); + } + + for (auto i=halfR; i!=end; ++i) + { + sLogDebug("debug", "R " << logVar(*i)); + } + + sLogDebug("debug", logVar(l) << logVar(r) << logVar(*i) << logVar(distance(l.center, *i))); + + { + auto sortable = translates_; + std::sort(sortable.begin(), sortable.end()); + + auto begin = sortable.begin(); + auto halfL = begin + sortable.size()/2; + auto halfR = halfL + 1; + auto l = sphereContaining_points(begin, halfR, Sphere1::Zero); + intersects(l, *i); + } + } + debug_assert(intersects(l, *i)); +// debug_assert(!intersects(r, *i)); + } + + for (auto i=halfR; i != end; ++i) + { + if (!intersects(r, *i)) + { + for (auto i=begin; i!=halfR; ++i) + { + sLogDebug("debug", "L " << logVar(*i)); + } + + for (auto i=halfR; i!=end; ++i) + { + sLogDebug("debug", "R " << logVar(*i)); + } + + sLogDebug("debug", logVar(l) << logVar(r) << logVar(*i) << logVar(distance(r.center, *i))); + auto r = sphereContaining_points(halfR, end, Sphere1::Zero); + intersects(r, *i); + } + + debug_assert(intersects(r, *i)); +// debug_assert(!intersects(l, *i)); + } +#endif + + return { l, r }; +} + +template +Sphere1 sphereContaining_spheres(I begin, I end, const Sphere1 &emptyValue) +{ + if (begin == end) + return emptyValue; + + auto c = begin->center; + + auto i=begin; + ++i; + + size_t count = 0; + for (;i!=end; ++i) + { + c = c + i->center; + count++; + } + + c = c / count; + auto radius = distance(begin->center, c) + begin->radius; + + i = begin; + ++i; + + for (;i!=end; ++i) + { + auto v = distance(i->center, c) + i->radius; + radius = max_value(radius, v); + } + + return { c, radius }; +} + +template +math::Sphere1 sphereContaining(const std::vector> &spheres, const math::Sphere1 &emptyValue) +{ + return sphereContaining_spheres(spheres.begin(), spheres.end(), emptyValue); +} + +template +math::Sphere3 sphereContaining(const math::Sphere3 &emptyValue, T &t, F &&f) +{ + std::vector> spheres; + for (auto &v : t) + spheres.push_back(f(v)); + + return sphereContaining(spheres, emptyValue); +} + +template +math::Sphere1 sphereContaining(const math::Sphere1 &emptyValue, T &t, F &&f) +{ + std::vector> spheres; + for (auto &v : t) + spheres.push_back(f(v)); + + return sphereContaining(spheres, emptyValue); +} + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Algorithm.cpp b/tjp/core/math/Algorithm.cpp new file mode 100755 index 0000000..a60b106 --- /dev/null +++ b/tjp/core/math/Algorithm.cpp @@ -0,0 +1,414 @@ +// +// Math.cpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#include "Algorithm.h" +#include "Sphere3.hpp" + +#include +#include + +#define GTE_NO_LOGGER +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "GTE_convert.hpp" + +#include + +namespace tjp { +namespace core { +namespace math { + +// --------------------------------- + +template +R distance_ (const math::Ray3 &ray, const math::Vector3 &r) +{ + auto ray_ = gte_c(ray); + auto point_ = gte_c(r); + + gte::DCPPoint3Ray3 query; + auto result = query(point_, ray_); + + return result.distance; +} + +template<> +r32 distance (const math::Ray3 &ray, const math::Vector3 &r) +{ + return distance_(ray, r); +} + +template<> +r64 distance (const math::Ray3 &ray, const math::Vector3 &r) +{ + return distance_(ray, r); +} + +// --------------------------------- + +template +R distance_ (const math::Segment3 &ray, const math::Vector3 &r) +{ + auto segment_ = gte_c(ray); + auto point_ = gte_c(r); + + gte::DCPPoint3Segment3 query; + auto result = query(point_, segment_); + + return result.distance; +} + +template<> +r32 distance (const math::Segment3 &ray, const math::Vector3 &r) +{ + return distance_(ray, r); +} + +template<> +r64 distance (const math::Segment3 &ray, const math::Vector3 &r) +{ + return distance_(ray, r); +} +// --------------------------------- + +template +bool intersects_ (const Sphere3 &sphere, const Frustum3 &frustum) +{ + auto sphere_ = gte_c(sphere); + auto frustum_ = gte_c(frustum); + + gte::TIQuery, gte::Frustum3> query; + auto result = query(sphere_, frustum_); + + return result.intersect; +} + +template +bool intersects_ (const Sphere3 &sphere, const Cone3 &cone) +{ + auto sphere_ = gte_c(sphere); + auto cone_ = gte_c(cone); + + gte::TIQuery, gte::Cone3> query; + auto result = query(sphere_, cone_); + + return result.intersect; +} + +template +bool intersects_ (const Box3 &lhs_, const Frustum3 &rhs_) +{ + auto lhs = gte_c(lhs_); + auto rhs = gte_c(rhs_); + + gte::TIQuery query; + auto result = query(lhs, rhs); + + return result.intersect; +} + +template +bool intersects_ (const Vector3 &point, const Frustum3 &frustum) +{ + auto frustum_ = gte_c(frustum); + auto point_ = gte_c(point); + + gte::DCPQuery, gte::Frustum3> query; + auto result = query(point_, frustum_); + return result.distance == 0; +} + +template +std::tuple> intersection_ (const Ray3 &ray, const Sphere3 &sphere) +{ + auto ray_ = gte_c(ray); + auto sphere_ = gte_c(sphere); + + gte::FIQuery, gte::Sphere3> query; + auto result = query(ray_, sphere_); + + if (result.intersect) + { + return { true, gte_c(result.point[0]) }; + } + + return { false, {} }; +} + +template +std::tuple> intersection_ (const Ray3 &ray, const Plane3 &plane) +{ + auto ray_ = gte_c(ray); + auto plane_ = gte_c(plane); + + gte::FIQuery, gte::Plane3> query; + auto result = query(ray_, plane_); + + if (result.intersect) + { + return { true, gte_c(result.point) }; + } + + return { false, {} }; +} + +template +std::tuple> intersection_ (const Sphere3 &l, const Sphere3 &r) +{ + auto l_ = gte_c(l); + auto r_ = gte_c(r); + + gte::FIQuery, gte::Sphere3> query; + auto result = query(l_, r_); + + if (result.intersect) + { + if (is_in(result.type, 1, 4, 6)) + { + return { true, { gte_c(result.point), math::Vector3::Zero, 0 } }; + } + return { true, gte_c(result.circle) }; + } + + return { false, {} }; +} + +// ------------------- + +//template<> +//bool intersects (const math::Vector3 &point, const math::Sphere3 &rhs) +//{ +// return intersects_(point, rhs); +//} +// +//template<> +//bool intersects (const math::Vector3 &point, const math::Sphere3 &rhs) +//{ +// return intersects_(point, rhs); +//} +// +template<> +bool intersects (const math::Sphere3 &sphere, const math::Frustum3 &rhs) +{ + return intersects_(sphere, rhs); +} + +template<> +bool intersects (const math::Sphere3 &sphere, const math::Frustum3 &rhs) +{ + return intersects_(sphere, rhs); +} + +template<> +bool intersects (const math::Sphere3 &sphere, const math::Cone3 &rhs) +{ + return intersects_(sphere, rhs); +} + +template<> +bool intersects (const math::Sphere3 &sphere, const math::Cone3 &rhs) +{ + return intersects_(sphere, rhs); +} + +template<> +bool intersects (const math::Box3 &lhs, const math::Frustum3 &rhs) +{ + return intersects_(lhs, rhs); +} + +template<> +bool intersects (const math::Box3 &lhs, const math::Frustum3 &rhs) +{ + return intersects_(lhs, rhs); +} + + +template<> +bool intersects (const math::Vector3 &point, const math::Frustum3 &rhs) +{ + return intersects_(point, rhs); +} + +template<> +bool intersects (const math::Vector3 &point, const math::Frustum3 &rhs) +{ + return intersects_(point, rhs); +} + +//template<> +//bool intersects (const math::Segment2 &segment, const math::Circle2 &rhs) +//{ +// return intersects_(segment, rhs); +//} +// +//template<> +//bool intersects (const math::Segment2 &segment, const math::Circle2 &rhs) +//{ +// return intersects_(segment, rhs); +//} + +template<> +std::tuple> intersection (const math::Ray3 &ray, const math::Sphere3 &rhs) +{ + return intersection_(ray, rhs); +} + +template<> +std::tuple> intersection (const math::Ray3 &ray, const math::Sphere3 &rhs) +{ + return intersection_(ray, rhs); +} + +template<> +std::tuple> intersection (const math::Ray3 &ray, const math::Plane3 &rhs) +{ + return intersection_(ray, rhs); +} + +template<> +std::tuple> intersection (const math::Ray3 &ray, const math::Plane3 &rhs) +{ + return intersection_(ray, rhs); +} + +// ---- + +template<> +std::tuple> intersection (const math::Sphere3 &lhs, const math::Sphere3 &rhs) +{ + return intersection_(lhs, rhs); +} + +template<> +std::tuple> intersection (const math::Sphere3 &lhs, const math::Sphere3 &rhs) +{ + return intersection_(lhs, rhs); +} + + +// ---- + +template +std::tuple> closest_(const math::Ray3 &ray, const math::Vector3 &point) +{ + auto ray_ = gte_c(ray); + auto point_ = gte_c(point); + + gte::DCPPoint3Ray3 dcp; + auto result = dcp(point_, ray_); + + gte::Vector3 &closest = result.rayClosest; + return { result.distance, gte_c(closest) }; +} + + +template<> +std::tuple> closest(const math::Ray3 &ray, const math::Vector3 &point) +{ + return closest_(ray, point); +} + +template<> +std::tuple> closest(const math::Ray3 &ray, const math::Vector3 &point) +{ + return closest_(ray, point); +} + + +template +std::tuple> closest_(const math::Segment3 &ray, const math::Vector3 &point) +{ + auto ray_ = gte_c(ray); + auto point_ = gte_c(point); + + gte::DCPPoint3Segment3 dcp; + auto result = dcp(point_, ray_); + + gte::Vector3 &closest = result.segmentClosest; + return { result.distance, gte_c(closest) }; +} + + +template<> +std::tuple> closest(const math::Segment3 &ray, const math::Vector3 &point) +{ + return closest_(ray, point); +} + +template<> +std::tuple> closest(const math::Segment3 &ray, const math::Vector3 &point) +{ + return closest_(ray, point); +} + +// ------------ + +template +std::tuple> closest_(const math::Plane3 &plane, const math::Vector3 &point) +{ + auto plane_ = gte_c(plane); + auto point_ = gte_c(point); + + gte::DCPQuery, gte::Plane3> dcp; + auto result = dcp(point_, plane_); + + gte::Vector3 &closest = result.planeClosestPoint; + return { result.distance, gte_c(closest) }; +} + +template<> +std::tuple> closest(const math::Plane3 &plane, const math::Vector3 &point) +{ + return closest_(plane, point); +} + +// ------------ + +template +Real distance_(const math::Triangle3 &plane, const math::Line3 &line) +{ + auto plane_ = gte_c(plane); + auto line_ = gte_c(line); + + gte::DCPQuery, gte::Triangle3> dcp; + auto result = dcp(line_, plane_); + + return result.distance; +} + +template<> +r64 distance(const math::Triangle3 &plane, const math::Line3 &line) +{ + return distance_(plane, line); +} + +// ------------ + +template<> +bool intersects(const math::Triangle3 &plane, const math::Ray3 &line, r64 epsilon) +{ + math::Line3 l = { line.origin, line.direction }; + return distance(plane, l) < epsilon; +} + +} // namespace +} // namespace +} // namespace diff --git a/tjp/core/math/Algorithm.h b/tjp/core/math/Algorithm.h new file mode 100755 index 0000000..2f9cc64 --- /dev/null +++ b/tjp/core/math/Algorithm.h @@ -0,0 +1,124 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Math.h" +#include "Sphere1.h" +#include "Sphere3.h" +#include "Vector3.h" +#include "Box3.h" +#include +#include + +#include "Epsilon.h" + +namespace tjp { +namespace core { +namespace math { + +template +std::tuple, math::Sphere3> bisectingRegions(const std::vector> &points); + +template +std::tuple, math::Sphere1> bisectingRegions(const std::vector &points); + + +template +math::Sphere3 sphereContaining(const std::vector> &spheres, const math::Sphere3 &emptyValue); + +template +math::Sphere3 sphereContaining(const std::vector> &spheres, const math::Sphere3 &emptyValue); + +template +math::Sphere1 sphereContaining(const std::vector> &spheres, const math::Sphere1 &emptyValue); + + +template +math::Sphere3 sphereContaining(const math::Sphere3 &emptyValue, T &t, F &&f); + +template +math::Sphere1 sphereContaining(const math::Sphere1 &emptyValue, T &t, F &&f); + + +// --------------------- + +template +Real distance (const math::Ray3 &ray, const math::Vector3 &r); + +template +Real distance (const math::Segment3 &ray, const math::Vector3 &r); + +template +bool intersects (const math::Sphere3 &sphere, const math::Cone3 &rhs); + +// --------------------- + +template +bool contains (const math::Sphere3 &parent, const math::Sphere3 &child, Real error = epsilon()); + +template +bool contains (const math::Sphere1 &parent, const math::Sphere1 &child, D error = epsilon()); + +// --------------------- + +template +bool intersects (const math::Sphere3 &sphere, const math::Sphere3 &rhs, Real error = epsilon()); + +template +bool intersects (const math::Sphere1 &sphere, const math::Sphere1 &rhs, D error = epsilon()); + +template +bool intersects (const math::Sphere1 &sphere, const C &rhs, D error = epsilon()); + +template +bool intersects(const math::Triangle3 &plane, const math::Ray3 &line, D error = epsilon()); + +// --------------------- + +template +bool intersects (const math::Vector3 &point, const math::Sphere3 &rhs); + +template +bool intersects (const math::Sphere3 &sphere, const math::Frustum3 &rhs); + +template +bool intersects (const math::Vector3 &point, const math::Frustum3 &rhs); + +template +bool intersects (const math::Box3 &rectangle, const math::Frustum3 &rhs); + +template +bool intersects (const math::Segment2 &segment, const math::Circle2 &rhs); + +template +std::tuple> intersection (const math::Ray3 &ray, const math::Sphere3 &rhs); + +template +std::tuple> intersection (const math::Ray3 &ray, const math::Plane3 &rhs); + +template +std::tuple> closest(const math::Ray3 &ray, const math::Vector3 &point); + +template +std::tuple> closest(const math::Segment3 &ray, const math::Vector3 &point); + +template +std::tuple> intersection (const math::Sphere3 &ray, const math::Sphere3 &rhs); + +template +std::tuple> closest(const math::Plane3 &plane, const math::Vector3 &point); + +template +Real distance(const math::Triangle3 &plane, const math::Line3 &line); + + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Algorithm.hpp b/tjp/core/math/Algorithm.hpp new file mode 100755 index 0000000..990f096 --- /dev/null +++ b/tjp/core/math/Algorithm.hpp @@ -0,0 +1,130 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Algorithm.h" +#include "Math.hpp" + +namespace tjp { +namespace core { +namespace math { + +template<> +r32 distance (const math::Ray3 &ray, const math::Vector3 &r); + +template<> +r64 distance (const math::Ray3 &ray, const math::Vector3 &r); + +template<> +r32 distance (const math::Segment3 &ray, const math::Vector3 &r); + +template<> +r64 distance (const math::Segment3 &ray, const math::Vector3 &r); + +template<> +std::tuple, math::Sphere3> bisectingRegions(const std::vector> &points); + +template<> +std::tuple, math::Sphere3> bisectingRegions(const std::vector> &points); + + +template<> +math::Sphere3 sphereContaining(const std::vector> &points, const math::Sphere3 &emptyValue); + +template<> +math::Sphere3 sphereContaining(const std::vector> &spheres, const math::Sphere3 &emptyValue); + +template<> +math::Sphere3 sphereContaining(const std::vector> &spheres, const math::Sphere3 &emptyValue); + + +template<> +bool intersects (const math::Vector3 &point, const math::Sphere3 &rhs); + +template<> +bool intersects (const math::Vector3 &point, const math::Sphere3 &rhs); + +template<> +bool intersects (const math::Sphere3 &sphere, const math::Frustum3 &rhs); + +template<> +bool intersects (const math::Sphere3 &sphere, const math::Frustum3 &rhs); + +template<> +bool intersects (const math::Box3 &rectangle, const math::Frustum3 &rhs); + +template<> +bool intersects (const math::Box3 &rectangle, const math::Frustum3 &rhs); + +template<> +bool intersects (const math::Vector3 &point, const math::Frustum3 &rhs); + +template<> +bool intersects (const math::Vector3 &point, const math::Frustum3 &rhs); + +template<> +bool intersects (const math::Sphere3 &sphere, const math::Cone3 &rhs); + +template<> +bool intersects (const math::Sphere3 &sphere, const math::Cone3 &rhs); + +template<> +bool intersects (const math::Segment2 &segment, const math::Circle2 &rhs); + +template<> +bool intersects (const math::Segment2 &segment, const math::Circle2 &rhs); + +template<> +std::tuple> intersection (const math::Ray3 &ray, const math::Sphere3 &rhs); + +template<> +std::tuple> intersection (const math::Ray3 &ray, const math::Sphere3 &rhs); + +template<> +std::tuple> intersection (const math::Ray3 &ray, const math::Plane3 &rhs); + +template<> +std::tuple> intersection (const math::Ray3 &ray, const math::Plane3 &rhs); + + +template<> +std::tuple> closest(const math::Ray3 &ray, const math::Vector3 &point); + +template<> +std::tuple> closest(const math::Ray3 &ray, const math::Vector3 &point); + +template<> +std::tuple> closest(const math::Segment3 &ray, const math::Vector3 &point); + +template<> +std::tuple> closest(const math::Segment3 &ray, const math::Vector3 &point); + + +template<> +std::tuple> intersection (const math::Sphere3 &ray, const math::Sphere3 &rhs); + +template<> +std::tuple> intersection (const math::Sphere3 &ray, const math::Sphere3 &rhs); + + +template<> +std::tuple> closest(const math::Plane3 &plane, const math::Vector3 &point); + +template<> +r64 distance(const math::Triangle3 &plane, const math::Line3 &line); + +template<> +bool intersects(const math::Triangle3 &plane, const math::Ray3 &line, r64 error); + + +} // namespace +} // namespace +} // namespace + +#include "Algorithm.inl" diff --git a/tjp/core/math/Algorithm.inl b/tjp/core/math/Algorithm.inl new file mode 100755 index 0000000..9395af9 --- /dev/null +++ b/tjp/core/math/Algorithm.inl @@ -0,0 +1,77 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Algorithm.h" +#include "Math.hpp" +//#include "BigInt.hpp" +//#include "BigDecimal.hpp" + +#include +#include "Vector3.inl" +#include "Real.inl" +#include "Distance.inl" + +namespace tjp { +namespace core { +namespace math { + +template +bool intersects_sphere (const S &l, const S &r, R error) +{ + return distance(l.center, r.center) <= (l.radius + r.radius) + error; +} + +template +bool intersects_sphere_point (const S &l, const U &r, R error) +{ + return distance(l.center, r) <= (l.radius) + error; +} + +template +bool intersects (const math::Sphere3 &l, const math::Sphere3 &r, Real error) +{ + return distance_squared(l.center, r.center) - math::pow2(l.radius + r.radius + error) <= 0; +} + +template +bool intersects (const math::Sphere1 &l, const C &r, D error) +{ + return intersects_sphere_point(l, r, error); +} + +template +bool intersects (const math::Sphere1 &l, const math::Sphere1 &r, D error) +{ + return intersects_sphere(l, r, error); +} + +template +bool contains_sphere (const S &l, const S &r, R error) +{ + return distance(l.center, r.center) + r.radius <= l.radius + error; +} + +template +bool contains (const math::Sphere3 &l, const math::Sphere3 &r, Real error) +{ + return contains_sphere(l, r, error); +} + +template +bool contains (const math::Sphere1 &l, const math::Sphere1 &r, D error) +{ + return contains_sphere(l, r, error); +} + + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Box3.h b/tjp/core/math/Box3.h new file mode 100755 index 0000000..248324b --- /dev/null +++ b/tjp/core/math/Box3.h @@ -0,0 +1,27 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Real.h" + +namespace tjp { +namespace core { +namespace math { + +template +class Box3; + +typedef Box3 Box3f; +typedef Box3 Box3d; +typedef Box3 Box3r; + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Box3.hpp b/tjp/core/math/Box3.hpp new file mode 100755 index 0000000..ef1f065 --- /dev/null +++ b/tjp/core/math/Box3.hpp @@ -0,0 +1,36 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Box3.h" + +#include + +namespace tjp { +namespace core { +namespace math { + +template +class Box3 +{ +public: + typedef Real value_type; + + typedef Vector3 Center; + Center center; + + using Axis = Vector3; + std::array axis; + std::array extent; +}; + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Distance+BigInt.inl b/tjp/core/math/Distance+BigInt.inl new file mode 100755 index 0000000..301618d --- /dev/null +++ b/tjp/core/math/Distance+BigInt.inl @@ -0,0 +1,140 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Vector3.inl" +#include "Vector2.hpp" +#include "Vector4.hpp" +#include "Real.inl" +#include "BigInt.hpp" +#include "BigDecimal.hpp" + + +namespace tjp { +namespace core { +namespace math { + +template +inline auto distance_squared(const Vector3 &l, const Vector3 &r) +{ + Real + a = r[0] - l[0], + b = r[1] - l[1], + c = r[2] - l[2]; + + return (a*a) + (b*b) + (c*c); +} + +template +inline auto distance_squared(const Vector4 &l, const Vector4 &r) +{ + Real + a = r[0] - l[0], + b = r[1] - l[1], + c = r[2] - l[2], + d = r[3] - l[3]; + + return (a*a) + (b*b) + (c*c) + (d*d); +} + + +template +inline auto distance_squared(const Vector2 &l, const Vector2 &r) +{ + Real + a = r[0] - l[0], + b = r[1] - l[1]; + + return (a*a) + (b*b); +} + +template +inline auto distance_squared(const Vector3 &r, Real x, Real y, Real z) +{ + Real a = r[0] - x; + a *= a; + + Real b = r[1] - y; + b *= b; + + Real c = r[2] - z; + c *= c; + + return a + b + c; +} + +template +inline auto distance(const Vector3 &r, Real x, Real y, Real z) +{ + return std::sqrt(distance_squared(r, x, y, z)); +} + +inline auto distance(const Vector3 &l, const Vector3 &r) { return sqrt(distance_squared(l, r)); } +inline auto distance(const Vector3 &l, const Vector3 &r) { return sqrt(distance_squared(l, r)); } + +inline auto distance(const Vector2 &l, const Vector2 &r) { return sqrt(distance_squared(l, r)); } +inline auto distance(const Vector2 &l, const Vector2 &r) { return sqrt(distance_squared(l, r)); } + +inline auto distance(const Vector4 &l, const Vector4 &r) { return sqrt(distance_squared(l, r)); } +inline auto distance(const Vector4 &l, const Vector4 &r) { return sqrt(distance_squared(l, r)); } + +// + +template +auto distance_vector_signed(const V &l, const V &r) +{ + return (r-l).length(); +} + +template +V distance_integral_unsigned(const V &l, const V &r) +{ + if (r > l) + return r - l; + + return l - r; +} + +template +V distance_integral_signed(const V &l, const V &r) +{ + return distance_integral_unsigned(l, r); +} + +// --------------------- + +inline auto distance(const Vector3 &l, const Vector3 &r) { return distance_vector_signed(l, r); } +inline auto distance(const Vector3 &l, const Vector3 &r) { return distance_vector_signed(l, r); } +inline auto distance(const Vector3 &l, const Vector3 &r) { return distance_vector_signed(l, r); } +inline auto distance(const Vector3 &l, const Vector3 &r) { return distance_vector_signed(l, r); } +inline auto distance(const Vector3 &l, const Vector3 &r) { return distance_vector_signed(l, r); } + +inline auto distance(const r32 &l, const r32 &r) { return distance_integral_signed(l, r); } +inline auto distance(const r64 &l, const r64 &r) { return distance_integral_signed(l, r); } +inline auto distance(const s32 &l, const s32 &r) { return distance_integral_signed(l, r); } +inline auto distance(const s64 &l, const s64 &r) { return distance_integral_signed(l, r); } +inline auto distance(const s128 &l, const s128 &r) { return distance_integral_signed(l, r); } + +inline auto distance(const u32 &l, const u32 &r) { return distance_integral_unsigned(l, r); } +inline auto distance(const u64 &l, const u64 &r) { return distance_integral_unsigned(l, r); } +inline auto distance(const u128 &l, const u128 &r) { return distance_integral_unsigned(l, r); } + +inline auto distance(const BigDecimal &l, const BigDecimal &r) { return distance_integral_signed(l, r); } + +template +auto distance_relative(const Real &l, const Real &r) +{ + return distance(l, r); +} + + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Distance.inl b/tjp/core/math/Distance.inl new file mode 100755 index 0000000..16836f3 --- /dev/null +++ b/tjp/core/math/Distance.inl @@ -0,0 +1,135 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Vector3.inl" +#include "Vector2.hpp" +#include "Vector4.hpp" +#include "Real.inl" + + +namespace tjp { +namespace core { +namespace math { + +template +inline auto distance_squared(const Vector3 &l, const Vector3 &r) +{ + Real + a = r[0] - l[0], + b = r[1] - l[1], + c = r[2] - l[2]; + + return (a*a) + (b*b) + (c*c); +} + +template +inline auto distance_squared(const Vector4 &l, const Vector4 &r) +{ + Real + a = r[0] - l[0], + b = r[1] - l[1], + c = r[2] - l[2], + d = r[3] - l[3]; + + return (a*a) + (b*b) + (c*c) + (d*d); +} + + +template +inline auto distance_squared(const Vector2 &l, const Vector2 &r) +{ + Real + a = r[0] - l[0], + b = r[1] - l[1]; + + return (a*a) + (b*b); +} + +template +inline auto distance_squared(const Vector3 &r, Real x, Real y, Real z) +{ + Real a = r[0] - x; + a *= a; + + Real b = r[1] - y; + b *= b; + + Real c = r[2] - z; + c *= c; + + return a + b + c; +} + +template +inline auto distance(const Vector3 &r, Real x, Real y, Real z) +{ + return std::sqrt(distance_squared(r, x, y, z)); +} + +inline auto distance(const Vector3 &l, const Vector3 &r) { return sqrt(distance_squared(l, r)); } +inline auto distance(const Vector3 &l, const Vector3 &r) { return sqrt(distance_squared(l, r)); } + +inline auto distance(const Vector2 &l, const Vector2 &r) { return sqrt(distance_squared(l, r)); } +inline auto distance(const Vector2 &l, const Vector2 &r) { return sqrt(distance_squared(l, r)); } + +inline auto distance(const Vector4 &l, const Vector4 &r) { return sqrt(distance_squared(l, r)); } +inline auto distance(const Vector4 &l, const Vector4 &r) { return sqrt(distance_squared(l, r)); } + +// + +template +auto distance_vector_signed(const V &l, const V &r) +{ + return (r-l).length(); +} + +template +V distance_integral_unsigned(const V &l, const V &r) +{ + if (r > l) + return r - l; + + return l - r; +} + +template +V distance_integral_signed(const V &l, const V &r) +{ + return distance_integral_unsigned(l, r); +} + +// --------------------- + +inline auto distance(const Vector3 &l, const Vector3 &r) { return distance_vector_signed(l, r); } +inline auto distance(const Vector3 &l, const Vector3 &r) { return distance_vector_signed(l, r); } +inline auto distance(const Vector3 &l, const Vector3 &r) { return distance_vector_signed(l, r); } + +inline auto distance(const r32 &l, const r32 &r) { return distance_integral_signed(l, r); } +inline auto distance(const r64 &l, const r64 &r) { return distance_integral_signed(l, r); } +inline auto distance(const s32 &l, const s32 &r) { return distance_integral_signed(l, r); } +inline auto distance(const s64 &l, const s64 &r) { return distance_integral_signed(l, r); } +inline auto distance(const s128 &l, const s128 &r) { return distance_integral_signed(l, r); } + +inline auto distance(const u32 &l, const u32 &r) { return distance_integral_unsigned(l, r); } +inline auto distance(const u64 &l, const u64 &r) { return distance_integral_unsigned(l, r); } +inline auto distance(const u128 &l, const u128 &r) { return distance_integral_unsigned(l, r); } + + +template +auto distance_relative(const Real &l, const Real &r) +{ + return distance(l, r); +} + + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Epsilon.h b/tjp/core/math/Epsilon.h new file mode 100755 index 0000000..b6d5810 --- /dev/null +++ b/tjp/core/math/Epsilon.h @@ -0,0 +1,69 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include + +namespace tjp { +namespace core { +namespace math { + +template +T epsilon() +{ + return T(0.00001); +} + +template<> +inline +s128 epsilon() +{ + return 1; +} + +template<> +inline +s64 epsilon() +{ + return 1; +} + +template<> +inline +s32 epsilon() +{ + return 1; +} + +template<> +inline +u128 epsilon() +{ + return 1; +} + +template<> +inline +u64 epsilon() +{ + return 1; +} + +template<> +inline +u32 epsilon() +{ + return 1; +} + + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Eulers.h b/tjp/core/math/Eulers.h new file mode 100755 index 0000000..62ae6f9 --- /dev/null +++ b/tjp/core/math/Eulers.h @@ -0,0 +1,25 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +namespace tjp { +namespace core { +namespace math { + +template +struct Eulers; + +typedef Eulers Eulersd; +typedef Eulers Eulersf; +typedef Eulers Eulersr; + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Eulers.hpp b/tjp/core/math/Eulers.hpp new file mode 100755 index 0000000..c515550 --- /dev/null +++ b/tjp/core/math/Eulers.hpp @@ -0,0 +1,40 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Eulers.h" +#include "Zero.h" +#include +#include + +#include +#include + +namespace tjp { +namespace core { +namespace math { + +template +struct Eulers { + Real pitch, yaw, roll; +} ; + +template +bool operator ==(const Eulers &lhs, const Eulers &rhs) +{ + return + lhs.pitch == rhs.pitch && + lhs.yaw == rhs.yaw && + lhs.roll == rhs.roll; +} + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/FastFourier.h b/tjp/core/math/FastFourier.h new file mode 100755 index 0000000..fedee65 --- /dev/null +++ b/tjp/core/math/FastFourier.h @@ -0,0 +1,20 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +namespace tjp { +namespace core { +namespace math { + +// https://rosettacode.org/wiki/Fast_Fourier_transform + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/FloatPack.inl b/tjp/core/math/FloatPack.inl new file mode 100755 index 0000000..b270b12 --- /dev/null +++ b/tjp/core/math/FloatPack.inl @@ -0,0 +1,135 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Vector2.inl" +#include "Vector3.inl" +#include "Vector4.inl" + +namespace tjp { +namespace core { +namespace math { + +constexpr int float_2_bits = 12; +constexpr int float_3_bits = 8; +constexpr int float_4_bits = 6; + +const float float_2_max = 1 << float_2_bits; +const Vector2f float_2_decoder = { 1, (1< +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace tjp { +namespace core { +namespace math { + +template +Vector3 gte_c (const gte::Vector3 &v) +{ + return { v[0], v[1], v[2] }; +} + +template +gte::Vector3 gte_c (const Vector3 &v) +{ + return { v[0], v[1], v[2] }; +} + +template +Circle2 gte_c (const gte::Circle2 &v) +{ + return { gte_c(v.center), v.radius }; +} + +template +gte::Circle2 gte_c (const Circle2 &v) +{ + return { gte_c(v.center), v.radius }; +} + +template +Circle3 gte_c (const gte::Circle3 &v) +{ + return { gte_c(v.center), gte_c(v.normal), v.radius }; +} + +template +gte::Circle3 gte_c (const Circle3 &v) +{ + return { gte_c(v.center), gte_c(v.normal), v.radius }; +} + +template +Sphere3 gte_c (const gte::Sphere3 &v) +{ + return { gte_c(v.center), v.radius }; +} + +template +gte::Sphere3 gte_c (const Sphere3 &v) +{ + return { gte_c(v.center), v.radius }; +} + +template +gte::OrientedBox<3, Real> gte_c (const Box3 &v) +{ + return { + gte_c(v.center), + { + gte_c(v.axis[0]), + gte_c(v.axis[1]), + gte_c(v.axis[2]) + }, + v.extent + }; +} + +template +Box3 gte_c (const gte::OrientedBox<3, Real> &v) +{ + return { + gte_c(v.center), + { + gte_c(v.axis[0]), + gte_c(v.axis[1]), + gte_c(v.axis[2]) + }, + v.extent + }; +} + + + +template +gte::Plane3 gte_c (const Plane3 &v) +{ + return { gte_c(v.normal), v.constant }; +} + +template +gte::Frustum3 gte_c (const Frustum3 &v) +{ + return { + gte_c(v.origin), + gte_c(v.dVector), + gte_c(v.uVector), + gte_c(v.rVector), + v.dMin, v.dMax, v.uBound, v.rBound + }; +} + +template +gte::Cone3 gte_c (const Cone3 &v) +{ + return { + gte_c(v.ray), + v.angle + }; +} + +template +gte::Triangle3 gte_c (const Triangle3 &v) +{ + return { + gte_c(v.v[0]), + gte_c(v.v[1]), + gte_c(v.v[2]) + }; +} + +template +Triangle3 gte_c (const gte::Triangle3 &v) +{ + return { + gte_c(v.v[0]), + gte_c(v.v[1]), + gte_c(v.v[2]) + }; +} + + +template +gte::Line3 gte_c (const Line3 &v) +{ + return { + gte_c(v.origin), + gte_c(v.direction) + }; +} + +template +Line3 gte_c (const gte::Line3 &v) +{ + return { + gte_c(v.origin), + gte_c(v.direction) + }; +} + +template +gte::Ray3 gte_c (const Ray3 &v) +{ + return { gte_c(v.origin), gte_c(v.direction) }; +} + +template +gte::Segment3 gte_c (const Segment3 &v) +{ + return { gte_c(v.begin), gte_c(v.end) }; +} + +} // namespace +} // namespace +} // namespace diff --git a/tjp/core/math/HMatrix.cpp b/tjp/core/math/HMatrix.cpp new file mode 100755 index 0000000..06c0f78 --- /dev/null +++ b/tjp/core/math/HMatrix.cpp @@ -0,0 +1,56 @@ +// +// Math.cpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#include "HMatrix.hpp" +#include "HMatrix.inl" + +namespace tjp { +namespace core { +namespace math { + +// inline +template<> +HMatrix operator *(const HMatrix &lhs, const HMatrix &rhs) +{ + HMatrix result; + + for (int r = 0; r < 4; ++r) + { + for (int c = 0; c < 4; ++c) + { + result[r][c] = 0; + + for (int i = 0; i < 4; ++i) + { + result[r][c] += lhs[i][c] * rhs[r][i]; + } + } + } + return result; +} + + +template<> +const HMatrix HMatrix::Zero { + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0 +}; + +template<> +const HMatrix HMatrix::Identity { + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 +}; + +} // namespace +} // namespace +} // namespace diff --git a/tjp/core/math/HMatrix.h b/tjp/core/math/HMatrix.h new file mode 100755 index 0000000..329b763 --- /dev/null +++ b/tjp/core/math/HMatrix.h @@ -0,0 +1,27 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Real.h" + +namespace tjp { +namespace core { +namespace math { + +template +class HMatrix; + +typedef HMatrix HMatrixr; +typedef HMatrix HMatrixf; +typedef HMatrix HMatrixd; + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/HMatrix.hpp b/tjp/core/math/HMatrix.hpp new file mode 100755 index 0000000..e77e949 --- /dev/null +++ b/tjp/core/math/HMatrix.hpp @@ -0,0 +1,78 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "HMatrix.h" +#include "Matrix3.h" +#include "Vector3.h" + +#include +#include + +namespace tjp { +namespace core { +namespace math { + +template +class HMatrix +{ +public: + typedef Real value_type; + + Real v[16]; + +public: + HMatrix(std::initializer_list l); + HMatrix(const Matrix3 &m, const Vector3 &t, const Vector3 &s); + HMatrix() {} + + const Real* operator[] (size_t row) const; + Real* operator[] (size_t row); + + static const HMatrix Zero; + static const HMatrix Identity; + + template + HMatrix asType() const + { + return HMatrix { + (U)v[0], (U)v[1], (U)v[2], (U)v[3], + (U)v[4], (U)v[5], (U)v[6], (U)v[7], + (U)v[8], (U)v[9], (U)v[10], (U)v[11], + (U)v[12], (U)v[13], (U)v[14], (U)v[15], + }; + } + +} ; + + +template +const HMatrix HMatrix::Zero = { + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0 +}; + +template +const HMatrix HMatrix::Identity = { + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 +}; + +typedef HMatrix HMatrixr; +typedef HMatrix HMatrixf; +typedef HMatrix HMatrixd; + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/HMatrix.inl b/tjp/core/math/HMatrix.inl new file mode 100755 index 0000000..6816139 --- /dev/null +++ b/tjp/core/math/HMatrix.inl @@ -0,0 +1,128 @@ +// +// Math.inl +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "HMatrix.hpp" +#include "HPoint.hpp" +#include "Zero.h" + +namespace tjp { +namespace core { +namespace math { + +// inline +template +HMatrix::HMatrix(std::initializer_list l) +{ + int i=0; + for (auto &r : l) + v[i++] = r; +} + + +// inline +template +HMatrix::HMatrix (const Matrix3 &m, const Vector3 &t, const Vector3 &s) +{ + Real vn[] { + m.v[0] * s[0], m.v[1] * s[1], m.v[2] * s[2], t[0], + m.v[3] * s[0], m.v[4] * s[1], m.v[5] * s[2], t[1], + m.v[6] * s[0], m.v[7] * s[1], m.v[8] * s[2], t[2], + 0, 0, 0, 1 + }; + + for (int i=0; i<16; ++i) + v[i] = vn[i]; +} + +// inline +template +HMatrix operator *(const HMatrix &lhs, const HMatrix &rhs); + +template<> +HMatrix operator *(const HMatrix &lhs, const HMatrix &rhs); + +template +Vector3 operator *(const HMatrix &hm, const Vector3 &p) +{ + HPoint hp(p); + auto v = hm * hp; + return { v.v[0], v.v[1], v.v[2] }; +} + +// inline +template +HPoint operator *(const HMatrix &m, const HPoint &p) +{ + return HPoint( + m.v[ 0]*p[0] + + m.v[ 1]*p[1] + + m.v[ 2]*p[2] + + m.v[ 3]*p[3], + + m.v[ 4]*p[0] + + m.v[ 5]*p[1] + + m.v[ 6]*p[2] + + m.v[ 7]*p[3], + + m.v[ 8]*p[0] + + m.v[ 9]*p[1] + + m.v[10]*p[2] + + m.v[11]*p[3], + + m.v[12]*p[0] + + m.v[13]*p[1] + + m.v[14]*p[2] + + m.v[15]*p[3]); +} + +// inline +template +HPoint operator* (const HPoint& p, const HMatrix& mat) +{ + return HPoint( + p[0]*mat[0][0] + p[1]*mat[1][0] + p[2]*mat[2][0] + p[3]*mat[3][0], + p[0]*mat[0][1] + p[1]*mat[1][1] + p[2]*mat[2][1] + p[3]*mat[3][1], + p[0]*mat[0][2] + p[1]*mat[1][2] + p[2]*mat[2][2] + p[3]*mat[3][2], + p[0]*mat[0][3] + p[1]*mat[1][3] + p[2]*mat[2][3] + p[3]*mat[3][3]); +} + +// inline +template +const Real* HMatrix::operator[] (size_t row) const +{ + return &v[4*row]; +} + +// inline +template +Real* HMatrix::operator[] (size_t row) +{ + return &v[4*row]; +} + +template +bool operator ==(const HMatrix &lhs, const HMatrix &rhs) +{ + for (auto i=0; i<16; ++i) + if (lhs.v[i] != rhs.v[i]) + return false; + + return true; +} + +template +bool operator !=(const HMatrix &lhs, const HMatrix &rhs) +{ + return !(lhs == rhs); +} + +} // namespace +} // namespace +} // namespace diff --git a/tjp/core/math/HPoint.h b/tjp/core/math/HPoint.h new file mode 100755 index 0000000..431ea6c --- /dev/null +++ b/tjp/core/math/HPoint.h @@ -0,0 +1,27 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Real.h" + +namespace tjp { +namespace core { +namespace math { + +template +struct HPoint; + +typedef HPoint HPointr; +typedef HPoint HPointf; +typedef HPoint HPointd; + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/HPoint.hpp b/tjp/core/math/HPoint.hpp new file mode 100755 index 0000000..ca5469a --- /dev/null +++ b/tjp/core/math/HPoint.hpp @@ -0,0 +1,44 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "HPoint.h" +#include "Vector3.h" + +namespace tjp { +namespace core { +namespace math { + +template +struct HPoint +{ + typedef Real value_type; + + Real v[4]; + + HPoint(); + + HPoint(const Vector3 &r); + HPoint(Real v0, Real v1, Real v2, Real v3); + + Real &operator[](size_t size); + Real const &operator[](size_t size) const; + + operator Vector3&(); + operator const Vector3&() const; +}; + +typedef HPoint HPointr; +typedef HPoint HPointf; +typedef HPoint HPointd; + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/HPoint.inl b/tjp/core/math/HPoint.inl new file mode 100755 index 0000000..30ea779 --- /dev/null +++ b/tjp/core/math/HPoint.inl @@ -0,0 +1,74 @@ +// +// Math.inl +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "HPoint.hpp" +#include "Zero.h" +#include "Vector3.hpp" + +namespace tjp { +namespace core { +namespace math { + + +template +HPoint::HPoint () +{ +} + +template +HPoint::HPoint(Real v0, Real v1, Real v2, Real v3) +{ + v[0] = v0; + v[1] = v1; + v[2] = v2; + v[3] = v3; +} + + +// inline +template +HPoint::HPoint(const Vector3 &r) +{ + v[0] = r.v[0]; + v[1] = r.v[1]; + v[2] = r.v[2]; + v[3] = 1; +} + +// inline +template +HPoint::operator Vector3&() +{ + return *(Vector3 *)this; +} + +template +HPoint::operator const Vector3&() const +{ + return *(const Vector3 *)this; +} + +// inline +template +Real &HPoint::operator[](size_t size) +{ + return v[size]; +} + +// inline +template +Real const &HPoint::operator[](size_t size) const +{ + return v[size]; +} + +} // namespace +} // namespace +} // namespace diff --git a/tjp/core/math/Math+IO.h b/tjp/core/math/Math+IO.h new file mode 100644 index 0000000..f3e2b61 --- /dev/null +++ b/tjp/core/math/Math+IO.h @@ -0,0 +1,259 @@ +// +// MathIO.h +// common +// +// Created by Timothy Prepscius on 8/4/18. +// Copyright © 2018 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Math.h" +#include +#include + +#include "Matrix3.hpp" +#include "HMatrix.hpp" +#include "HPoint.hpp" +#include "Vector3.hpp" +#include "Sphere3.hpp" +#include "Sphere1.hpp" +#include "Segment1.hpp" +#include "Vector4.hpp" + +namespace tjp { +namespace core { +namespace math { + +template +std::ostream &operator <<(std::ostream &o, const HMatrix &v) +{ + for (auto i=0; i<4; ++i) + { + o << "["; + o << v[i][0]; + for (auto j=1; j<4; ++j) + { + o << ","; + o << v[i][j]; + } + o << "]"; + } + + return o; +} + +template +std::ostream &operator <<(std::ostream &o, const Vector3 &v) +{ + o << v[0]; + for (auto j=1; j<3; ++j) + { + o << ","; + o << v[j]; + } + + return o; +} + +template +std::ostream &operator <<(std::ostream &o, const Vector4 &v) +{ + o << v[0]; + for (auto j=1; j<4; ++j) + { + o << ","; + o << v[j]; + } + + return o; +} + +template +std::ostream &operator <<(std::ostream &o, const HPoint &v) +{ + o << "("; + o << v[0]; + for (auto j=1; j<4; ++j) + { + o << ","; + o << v[j]; + } + o << ")"; + + return o; +} + +template +std::ostream &operator <<(std::ostream &o, const Vector2 &v) +{ + o << v[0]; + for (auto j=1; j<2; ++j) + { + o << ","; + o << v[j]; + } + + return o; +} + + +template +std::ostream &operator <<(std::ostream &o, const Matrix3 &v) +{ + for (auto i=0; i<3; ++i) + { + o << "["; + o << v[i][0]; + for (auto j=1; j<3; ++j) + { + o << ","; + o << v[i][j]; + } + o << "]"; + } + + return o; +} + +template +std::ostream &operator <<(std::ostream &o, const Sphere3 &v) +{ + o << "{" << v.center << ":" << v.radius << "}"; + return o; +} + +template +std::ostream &operator <<(std::ostream &o, const Sphere1 &v) +{ + o << "{" << v.center << ":" << v.radius << "}"; + return o; +} + +template +std::ostream &operator <<(std::ostream &o, const Segment1 &v) +{ + o << "{" << v.begin << "," << v.end << "}"; + return o; +} + +// ---------------------------------------------------- + +template +void io_(IO &io, math::Vector2 &m) +{ + io.array(m.v[0], m.v[1]); +} + +template +void io_(IO &io, math::Vector3 &m) +{ + io.array(m.v[0], m.v[1], m.v[2]); +} + +template +void io_(IO &io, math::Vector4 &m) +{ + io.array(m.v[0], m.v[1], m.v[2], m.v[3]); +} + +template +void io_(IO &io, math::Plane3 &m) +{ + io.object("normal", m.normal, "constant", m.constant); +} + +template +void io_(IO &io, math::Sphere3 &m) +{ + io.object("center", m.center, "radius", m.radius); +} + +template +void io_(IO &io, math::Sphere1 &m) +{ + io.object("center", m.center, "radius", m.radius); +} + +template +void io_(IO &io, math::Segment1 &m) +{ + io.object("begin", m.begin, "end", m.end); +} + +template +void io_(IO &io, math::HMatrix &m) +{ + io.array( + m.v[0], m.v[1], m.v[2], m.v[3], + m.v[4], m.v[5], m.v[6], m.v[7], + m.v[8], m.v[9], m.v[10], m.v[11], + m.v[12], m.v[13], m.v[14], m.v[15] + ); +} + +// ---------------------------------------------------- + +template +void io_bin(IO &io, math::Vector2 &m) { return io_(io, m); } + +template +void io_json(IO &io, math::Vector2 &m) { return io_(io, m); } + + +template +void io_bin(IO &io, math::Vector3 &m) { return io_(io, m); } + +template +void io_json(IO &io, math::Vector3 &m) { return io_(io, m); } + + +template +void io_bin(IO &io, math::Vector4 &m) { return io_(io, m); } + +template +void io_json(IO &io, math::Vector4 &m) { return io_(io, m); } + + +template +void io_bin(IO &io, math::Plane3 &m) { return io_(io, m); } + +template +void io_json(IO &io, math::Plane3 &m) { return io_(io, m); } + + +template +void io_bin(IO &io, math::Sphere1 &m) { return io_(io, m); } + +template +void io_json(IO &io, math::Sphere1 &m) { return io_(io, m); } + + +template +void io_bin(IO &io, math::Segment1 &m) { return io_(io, m); } + +template +void io_json(IO &io, math::Segment1 &m) { return io_(io, m); } + + +template +void io_bin(IO &io, math::Sphere3 &m) { return io_(io, m); } + +template +void io_json(IO &io, math::Sphere3 &m) { return io_(io, m); } + + +template +void io_bin(IO &io, math::HMatrix &m) { return io_(io, m); } + +template +void io_json(IO &io, math::HMatrix &m) { return io_(io, m); } + + +// ---------------------------------------------------- + + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Math+V.h b/tjp/core/math/Math+V.h new file mode 100644 index 0000000..6643dcc --- /dev/null +++ b/tjp/core/math/Math+V.h @@ -0,0 +1,28 @@ +// +// MathIO.h +// common +// +// Created by Timothy Prepscius on 8/4/18. +// Copyright © 2018 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Math.h" +#include + +#include "Vector3.h" +#include "Vector2.h" +#include "Sphere3.h" + +namespace tjp { +namespace core { +namespace math { + +extern const VType Vector3r_vtype; +extern const VType Sphere3s16_vtype; + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Math.h b/tjp/core/math/Math.h new file mode 100755 index 0000000..e1d9b34 --- /dev/null +++ b/tjp/core/math/Math.h @@ -0,0 +1,89 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Real.h" +# + +namespace tjp { +namespace core { +namespace math { + +template +struct constants; + +template +struct Ray3; + +template +struct Segment3; + +template +struct Line3; + +template +class Plane3; + +template +class Cone3; + +template +class Frustum3; + +template +struct Box3; + +template +struct Segment2; + +template +class Circle2; + +template +class Circle3; + +template +class Triangle3; + +typedef Ray3 Ray3d; +typedef Ray3 Ray3f; +typedef Ray3 Ray3r; + +typedef Segment2 Segment2d; +typedef Segment2 Segment2f; +typedef Segment2 Segment2r; + +typedef Circle2 Circle2d; +typedef Circle2 Circle2f; +typedef Circle2 Circle2r; + +typedef Line3 Line3d; +typedef Line3 Line3f; +typedef Line3 Line3r; + +typedef Plane3 Plane3f; +typedef Plane3 Plane3d; +typedef Plane3 Plane3r; + +typedef Triangle3 Triangle3f; +typedef Triangle3 Triangle3d; +typedef Triangle3 Triangle3r; + +typedef Cone3 Cone3f; +typedef Cone3 Cone3d; +typedef Cone3 Cone3r; + +typedef Frustum3 Frustum3d; +typedef Frustum3 Frustum3f; +typedef Frustum3 Frustum3r; + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Math.hpp b/tjp/core/math/Math.hpp new file mode 100755 index 0000000..16080cb --- /dev/null +++ b/tjp/core/math/Math.hpp @@ -0,0 +1,228 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Vector3.hpp" +#include "Vector2.hpp" +#include +#include + +namespace tjp { +namespace core { +namespace math { + +template +struct Ray3 +{ + Vector3 origin, direction; +} ; + +template +struct Line3 +{ + Vector3 origin, direction; +} ; + +template +class Plane3 +{ +public: + typedef Real value_type; + + Vector3 normal; + Real constant; + + Plane3 () {} + + Plane3 (const Vector3 &normal_, Real constant_) : + normal(normal_), + constant(constant_) + { + + } + + Plane3 (const Vector3 &o, const Vector3 &d) + { + normal = d; + constant = d * o; + } + + Plane3 (const Vector3 &p0, const Vector3 &p1, const Vector3 &p2) + { + auto v1 = p2 - p0; + auto v2 = p1 - p0; + normal = (v1 ^ v2).normalize(); + constant = normal * p0; + } + + int whichSide(const Vector3 &p) const; + Real distanceTo (const Vector3 &p) const; + + Vector3 closestPoint(const Vector3 &v) const; + +}; + +template +class Frustum3 +{ +public: + typedef Real value_type; + + Vector3 origin, dVector, uVector, rVector; + Real dMin, dMax, uBound, rBound; + + template + Frustum3 asType() const + { + return Frustum3 { + origin.template asType(), + dVector.template asType(), + uVector.template asType(), + rVector.template asType(), + (U)dMin, (U)dMax, (U)uBound, (U)rBound + }; + } +} ; + +//template +//struct Box3 +//{ +// typedef Real value_type; +// +// Vector3 center; +// std::array, 3> axis; +// Vector3 extent; +//} ; + +template +struct Cone3 +{ + typedef Real value_type; + + Ray3 ray; + Real angle; +} ; + +template +struct Segment2 +{ + typedef Real value_type; + + Vector2 begin, end; +} ; + +template +struct Segment3 +{ + typedef Real value_type; + + Vector3 begin, end; +} ; + +template +class Circle2 +{ +public: + typedef Real value_type; + + Vector2 center; + Real radius; + + Circle2 () {} + + Circle2 (const Vector2 ¢er_, Real radius_) : + center(center_), + radius(radius_) + { + } + + const static Circle2 Zero; +}; + +template +class Circle3 +{ +public: + typedef Real value_type; + + Vector3 center; + Vector3 normal; + Real radius; + + Circle3 () {} + + Circle3 (const Vector3 ¢er_, const Vector3 &normal_, Real radius_) : + center(center_), + normal(normal_), + radius(radius_) + { + } + + const static Circle3 Zero; +}; + +template +const Circle3 Circle3::Zero = { + Vector3::Zero, Vector3::Zero, 0 +}; + + +template +class Triangle3 +{ +public: + Vector3 v[3]; + + Vector3 normal() const + { + auto s0 = v[0] - v[1]; + auto s1 = v[0] - v[2]; + + return cross(s0, s1); + } +} ; + +typedef double Real; + +const Real Meter = 1.0; +const Real Centimeter = 0.01; +const Real Millimeter = 0.001; + +typedef Ray3 Ray3d; +typedef Ray3 Ray3f; +typedef Ray3 Ray3r; + +typedef Segment2 Segment2d; +typedef Segment2 Segment2f; +typedef Segment2 Segment2r; + +typedef Circle2 Circle2d; +typedef Circle2 Circle2f; +typedef Circle2 Circle2r; + +typedef Line3 Line3d; +typedef Line3 Line3f; +typedef Line3 Line3r; + +typedef Plane3 Plane3f; +typedef Plane3 Plane3d; +typedef Plane3 Plane3r; + +typedef Cone3 Cone3f; +typedef Cone3 Cone3d; +typedef Cone3 Cone3r; + +typedef Frustum3 Frustum3d; +typedef Frustum3 Frustum3f; +typedef Frustum3 Frustum3r; + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Math.inl b/tjp/core/math/Math.inl new file mode 100755 index 0000000..9bd6ab1 --- /dev/null +++ b/tjp/core/math/Math.inl @@ -0,0 +1,100 @@ +// +// Math.inl +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Math.hpp" +#include "Zero.h" + +namespace tjp { +namespace core { +namespace math { + +// inline +template +Real Plane3::distanceTo (const Vector3& p) const +{ + return (normal * p) - constant; +} + +// inline +template +int Plane3::whichSide (const Vector3 & p) const +{ + Real distance = distanceTo(p); + + if (distance < 0.0f) + { + return -1; + } + else if (distance > 0.0f) + { + return +1; + } + else + { + return 0; + } +} + +// inline +template +Real angleBetween (const Vector3 &l, const Vector3 &r) +{ + auto v1 = l.normalize(); + auto v2 = r.normalize(); + // | unit(V1) * unit(V2) | = cos A + double cosA = v1 * v2; + // if the shadow is completely in the same direction, then the + // difference in angle is zero + const double episolon = 0.00001; + const auto oneMepsilon = 1 - episolon; + const auto negOneMepsilon = -1 + episolon; + + if (cosA >= oneMepsilon) + return 0; + // if the shadow is completely in the opposite direction, then the + // difference in angle is PI + if (cosA <= negOneMepsilon) + return constants::PI; + + double Acos = acos(cosA); + return (Real) Acos; +} + +// inline +template +Vector3 axisBetween (const Vector3 &l, const Vector3 &r) +{ + return (l ^ r).normalize(); +} + + +// inline +template +Vector3 Plane3::closestPoint (const Vector3 &p) const +{ + // http://stackoverflow.com/questions/9605556/how-to-project-a-3d-point-to-a-3d-plane + + auto r = p - (normal * p + constant) * normal; + return r; +} + +// -------- + +template +Real area(const math::Triangle3 &t) +{ + auto e0 = t.v[1] - t.v[0]; + auto e1 = t.v[2] - t.v[0]; + return length(cross(e0, e1)) / 2; +} + +} // namespace +} // namespace +} // namespace diff --git a/tjp/core/math/MathGlmC.h b/tjp/core/math/MathGlmC.h new file mode 100755 index 0000000..290aae6 --- /dev/null +++ b/tjp/core/math/MathGlmC.h @@ -0,0 +1,102 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "HPoint.hpp" +#include "HMatrix.hpp" +#include "Vector3.hpp" +#include "Vector4.hpp" + +#include + +namespace tjp { +namespace core { +namespace math { + +template +glm::vec<3, T> glm_c(const math::Vector3 &v) +{ + return { v[0], v[1], v[2] }; +} + +template +math::Vector3 glm_c(const glm::vec<3, T> &v) +{ + return { v[0], v[1], v[2] }; +} + +template +glm::qua glm_c(const math::Vector4 &v) +{ + return { v[0], v[1], v[2], v[3] }; +} + +template +math::Vector4 glm_c(const glm::qua &v) +{ + return { v[0], v[1], v[2], v[3] }; +} + +template +glm::vec<4, T> glm_c(const math::HPoint &v) +{ + return { v[0], v[1], v[2], v[3] }; +} + +template +math::HPoint glm_c(const glm::vec<4, T> &v) +{ + return { v[0], v[1], v[2], v[3] }; +} + +template +glm::mat<3, 3, T> glm_c(const math::Matrix3 &m) +{ + return { + m[0][0], m[0][1], m[0][2], + m[1][0], m[1][1], m[1][2], + m[2][0], m[2][1], m[2][2] + } ; +} + +template +math::Matrix3 glm_c(const glm::mat<3, 3, T> &m) +{ + return { + m[0][0], m[0][1], m[0][2], + m[1][0], m[1][1], m[1][2], + m[2][0], m[2][1], m[2][2] + } ; +} +template +glm::mat<4, 4, T> glm_c(const math::HMatrix &m) +{ + return { + m[0][0], m[0][1], m[0][2], m[0][3], + m[1][0], m[1][1], m[1][2], m[1][3], + m[2][0], m[2][1], m[2][2], m[2][3], + m[3][0], m[3][1], m[3][2], m[3][3] + } ; +} + +template +math::HMatrix glm_c(const glm::mat<4, 4, T> &m) +{ + return { + m[0][0], m[0][1], m[0][2], m[0][3], + m[1][0], m[1][1], m[1][2], m[1][3], + m[2][0], m[2][1], m[2][2], m[2][3], + m[3][0], m[3][1], m[3][2], m[3][3] + } ; +} + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Matrix3.cpp b/tjp/core/math/Matrix3.cpp new file mode 100755 index 0000000..94484ed --- /dev/null +++ b/tjp/core/math/Matrix3.cpp @@ -0,0 +1,32 @@ +// +// Math.cpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#include "Matrix3.hpp" + +namespace tjp { +namespace core { +namespace math { + + +template<> +const Matrix3 Matrix3::Zero { + 0, 0, 0, + 0, 0, 0, + 0, 0, 0 +}; + +template<> +const Matrix3 Matrix3::Identity { + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 +}; + +} // namespace +} // namespace +} // namespace diff --git a/tjp/core/math/Matrix3.h b/tjp/core/math/Matrix3.h new file mode 100755 index 0000000..71c6ffb --- /dev/null +++ b/tjp/core/math/Matrix3.h @@ -0,0 +1,25 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +namespace tjp { +namespace core { +namespace math { + +template +class Matrix3; + +typedef Matrix3 Matrix3r; +typedef Matrix3 Matrix3f; +typedef Matrix3 Matrix3d; + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Matrix3.hpp b/tjp/core/math/Matrix3.hpp new file mode 100755 index 0000000..6852ff6 --- /dev/null +++ b/tjp/core/math/Matrix3.hpp @@ -0,0 +1,70 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Vector3.hpp" +#include +#include + +namespace tjp { +namespace core { +namespace math { + +template +class Matrix3 +{ +public: + typedef Real value_type; + + Real v[9]; + +public: + Matrix3(std::initializer_list l) + { + int i=0; + for (auto &r: l) + v[i++] = r; + } + + Matrix3 (const Vector3 &a, const Vector3 &b); + Matrix3 (const Vector3 &a, const Vector3 &b, const Vector3 &c); + Matrix3 () {} + + const Real* operator[] (size_t row) const; + Real* operator[] (size_t row); + + Matrix3 transpose() const; + Matrix3 inverse(Real epsilon) const; + + static const Matrix3 Zero; + static const Matrix3 Identity; +} ; + +template +const Matrix3 Matrix3::Zero = { + 0, 0, 0, + 0, 0, 0, + 0, 0, 0 +}; + +template +const Matrix3 Matrix3::Identity = { + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 +}; + +typedef Matrix3 Matrix3r; +typedef Matrix3 Matrix3f; +typedef Matrix3 Matrix3d; + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Matrix3.inl b/tjp/core/math/Matrix3.inl new file mode 100755 index 0000000..379c4ea --- /dev/null +++ b/tjp/core/math/Matrix3.inl @@ -0,0 +1,200 @@ +// +// Math.inl +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// +#pragma once + +#include "Matrix3.hpp" +#include "HPoint.hpp" +#include "Zero.h" + +#include + + +#include "HMatrix.inl" + +namespace tjp { +namespace core { +namespace math { + +//// inline +//template +//Matrix3::Matrix3(std::initializer_list l) +//{ +// int i=0; +// for (auto &r : l) +// v[i++] = r; +//} + +/* +// inline +template +Matrix3::Matrix3 (const Vector3 &a, const Vector3 &b) +{ + // http://gamedev.stackexchange.com/questions/20097/how-to-calculate-a-3x3-rotation-matrix-from-2-direction-vectors + + auto x = a.normalize(); + auto y = b.normalize(); + + Matrix3 &m = *this; + + Vector3 *mx = (Vector3 *)m[0]; + Vector3 *my = (Vector3 *)m[1]; + Vector3 *mz = (Vector3 *)m[2]; + + *mx = x; + *mz = (x^y).normalize(); + *my = (*mz ^ x).normalize(); +} +*/ + +template +Matrix3::Matrix3 (const Vector3 &a, const Vector3 &b, const Vector3 &c) +{ + v[0] = a[0]; + v[1] = a[1]; + v[2] = a[2]; + v[3] = b[0]; + v[4] = b[1]; + v[5] = b[2]; + v[6] = c[0]; + v[7] = c[1]; + v[8] = c[2]; +} + + +// inline +template +Matrix3::Matrix3 (const Vector3 &a, const Vector3 &b) +{ + // http://math.stackexchange.com/questions/180418/calculate-rotation-matrix-to-align-vector-a-to-vector-b-in-3d + + auto acb = a ^ b; + auto s = acb.length(); + auto c = a * b; + + Real vn[] { + c, -s, 0, + s, c, 0, + 0, 0, 1 + }; + + for (int i=0; i<9; ++i) + v[i] = vn[i]; +} + +template +Matrix3 rotationMatrix(const Vector3 &axis, const Real &angle) +{ + Real cosTheta = std::cos(angle); + Real sinTheta = std::sin(angle); + Real oneMinusCosTheta = 1 - cosTheta; + + Real x = axis[0]; + Real y = axis[1]; + Real z = axis[2]; + + Matrix3 result; + result[0][0] = cosTheta + x * x * oneMinusCosTheta; + result[0][1] = x * y * oneMinusCosTheta - z * sinTheta; + result[0][2] = x * z * oneMinusCosTheta + y * sinTheta; + + result[1][0] = y * x * oneMinusCosTheta + z * sinTheta; + result[1][1] = cosTheta + y * y * oneMinusCosTheta; + result[1][2] = y * z * oneMinusCosTheta - x * sinTheta; + + result[2][0] = z * x * oneMinusCosTheta - y * sinTheta; + result[2][1] = z * y * oneMinusCosTheta + x * sinTheta; + result[2][2] = cosTheta + z * z * oneMinusCosTheta; + + return result; +} + +// inline +template +Matrix3 Matrix3::transpose() const +{ + return Matrix3({ + v[0], + v[3], + v[6], + v[1], + v[4], + v[7], + v[2], + v[5], + v[8] + }); +} + +// inline +template +Matrix3 Matrix3::inverse(const Real epsilon) const +{ + // Invert a 3x3 using cofactors. This is faster than using a generic + // Gaussian elimination because of the loop overhead of such a method. + + Matrix3 inverse; + + // Compute the adjoint. + inverse.v[0] = v[4]*v[8] - v[5]*v[7]; + inverse.v[1] = v[2]*v[7] - v[1]*v[8]; + inverse.v[2] = v[1]*v[5] - v[2]*v[4]; + inverse.v[3] = v[5]*v[6] - v[3]*v[8]; + inverse.v[4] = v[0]*v[8] - v[2]*v[6]; + inverse.v[5] = v[2]*v[3] - v[0]*v[5]; + inverse.v[6] = v[3]*v[7] - v[4]*v[6]; + inverse.v[7] = v[1]*v[6] - v[0]*v[7]; + inverse.v[8] = v[0]*v[4] - v[1]*v[3]; + + Real det = v[0]*inverse.v[0] + v[1]*inverse.v[3] + + v[2]*inverse.v[6]; + + if (std::abs(det) > epsilon) + { + Real invDet = ((Real)1)/det; + inverse.v[0] *= invDet; + inverse.v[1] *= invDet; + inverse.v[2] *= invDet; + inverse.v[3] *= invDet; + inverse.v[4] *= invDet; + inverse.v[5] *= invDet; + inverse.v[6] *= invDet; + inverse.v[7] *= invDet; + inverse.v[8] *= invDet; + return inverse; + } + + return Zero; +} + +// inline +template +Vector3 operator *(const Matrix3 &m, const Vector3 &p) +{ + HMatrix hm(m, Vector3::Zero, { 1, 1, 1 }); + HPoint hp(p); + auto v = hm * hp; + return { v.v[0], v.v[1], v.v[2] }; +} + +// inline +template +const Real* Matrix3::operator[] (size_t row) const +{ + return &v[3*row]; +} + +// inline +template +Real* Matrix3::operator[] (size_t row) +{ + return &v[3*row]; +} + +} // namespace +} // namespace +} // namespace diff --git a/tjp/core/math/Precision.h b/tjp/core/math/Precision.h new file mode 100644 index 0000000..4ace16c --- /dev/null +++ b/tjp/core/math/Precision.h @@ -0,0 +1,44 @@ +// +// MathIO.h +// common +// +// Created by Timothy Prepscius on 8/4/18. +// Copyright © 2018 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Real.h" + +#include "Accuracy+IO.h" + +namespace tjp { +namespace core { +namespace math { + +template +struct Precision +{ + V v; + + operator V&() + { + return *this; + } + + operator const V&() const + { + return *this; + } +} ; + +template +void io_ (IO &io, Precision &v) +{ + io.any(with_accuracy(v, M)); +} + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Real.cpp b/tjp/core/math/Real.cpp new file mode 100755 index 0000000..c9153dd --- /dev/null +++ b/tjp/core/math/Real.cpp @@ -0,0 +1,86 @@ +// +// Math.cpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#include "Math.hpp" +#include "Real.hpp" +#include "Real.inl" +#include + +namespace tjp { +namespace core { +namespace math { + +// http://www.codecodex.com/wiki/Calculate_an_integer_square_root +template +T IntSqrt(T v) +{ + T remainder = v; + if (remainder < 0) { return 0; } + + T one = 1; + T place = one <<(sizeof(T)*8 -2); + + while (place > remainder) { place /= 4; } + + T root = 0; + while (place) + { + if (remainder >= root + place) + { + remainder -= root + place; + root += place*2; + } + root /= 2; + place /= 4; + } + return root; +} + +// float + +template<> +u128 sqrt(const u128 &v) +{ + return IntSqrt(v); +} + +template<> +s128 sqrt(const s128 &v) +{ + return IntSqrt(v); +} + + +template<> +const double tjp::core::math::constants::PI = atan(1)*4.0; + +template<> +const float tjp::core::math::constants::PI = atan(1)*4.0; + +template<> +const double tjp::core::math::constants::TWO_PI = atan(1)*8.0; + +template<> +const float tjp::core::math::constants::TWO_PI = atan(1)*8.0; + +template<> +const float tjp::core::math::constants::DEGREES_TO_RADIANS = 4.0 / 180.0 * atan(1); + +template<> +const float tjp::core::math::constants::RADIANS_TO_DEGREES = 180.0 / 4.0 / atan(1); + +template<> +const double tjp::core::math::constants::DEGREES_TO_RADIANS = 4.0 / 180.0 * atan(1); + +template<> +const double tjp::core::math::constants::RADIANS_TO_DEGREES = 180.0 / 4.0 / atan(1); + + +} // namespace +} // namespace +} // namespace diff --git a/tjp/core/math/Real.h b/tjp/core/math/Real.h new file mode 100755 index 0000000..0d0212a --- /dev/null +++ b/tjp/core/math/Real.h @@ -0,0 +1,83 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include +#include + +namespace tjp { +namespace core { +namespace math { + +typedef r64 Real; + +template +Real abs(const Real &); + +template +Real sqrt(const Real &); + +template +Real sin(const Real &); + +template +Real cos(const Real &); + +template +Real ceil(const Real &); + +template +Real floor(const Real &); + +template +Real acos(const Real &); + +template +Real atan(const Real &); + +template +Real atan2(const Real &, const Real &); + +template +Real hypot(const Real &, const Real &); + +template +Real pow2(const Real &); + +template +Real length(const Real &); + +template +Real min_value(const Real &lhs, const Real &rhs); + +template +Real max_value(const Real &lhs, const Real &rhs); + +template +math::Real toReal (const T &v) +{ + return (math::Real)v; +} + +template<> +u128 abs(const u128 &v); + +template<> +s128 abs(const s128 &v); + +template<> +u128 sqrt(const u128 &v); + +template<> +s128 sqrt(const s128 &v); + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Real.hpp b/tjp/core/math/Real.hpp new file mode 100755 index 0000000..6d60b52 --- /dev/null +++ b/tjp/core/math/Real.hpp @@ -0,0 +1,43 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Real.h" +#include "Zero.h" + +namespace tjp { +namespace core { +namespace math { + +template +struct constants { + static const Real PI; + static const Real TWO_PI; + + static const Real DEGREES_TO_RADIANS; + static const Real RADIANS_TO_DEGREES; +} ; + +template<> +const double tjp::core::math::constants::PI; + +template<> +const float tjp::core::math::constants::PI; + +template<> +const double tjp::core::math::constants::TWO_PI; + +template<> +const float tjp::core::math::constants::TWO_PI; + +} // namespace +} // namespace +} // namespace + +#include "Real.inl" diff --git a/tjp/core/math/Real.inl b/tjp/core/math/Real.inl new file mode 100755 index 0000000..0c3cec8 --- /dev/null +++ b/tjp/core/math/Real.inl @@ -0,0 +1,174 @@ +// +// Math.inl +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +// inline + +#pragma once + +#include "Real.hpp" + +#include +#include + +namespace tjp { +namespace core { +namespace math { + +template +T clamp(const T &t, T l=0, T r=1) +{ + return std::min(std::max(t, l), r); +} + +template +Real ceil(const Real &r) +{ + return std::ceil(r); +} + +template +Real floor(const Real &r) +{ + return std::floor(r); +} + +template +Real trunc(const Real &r) +{ + return std::trunc(r); +} + + +template +Real pow2(const Real &r) +{ + return r*r; +} + +template +Real min_value(const Real &lhs, const Real &rhs) +{ + if (lhs < rhs) + return lhs; + + return rhs; +} + +template +Real max_value(const Real &lhs, const Real &rhs) +{ + if (lhs > rhs) + return lhs; + + return rhs; +} + + +template +Real sign_of(const Real & a) +{ + if (a < 0) + return (Real)-1; + + return 1; +} + +template +Real abs(const Real & a) +{ + return std::abs(a); +} + +template +Real sin(const Real & a) +{ + return std::sin(a); +} + +// inline +template +Real cos(const Real & a) +{ + return std::cos(a); +} + +// inline +template +Real sqrt(const Real &v) +{ + return std::sqrt(v); +} + +// inline +template +Real acos(const Real & v) +{ + return std::acos(v); +} + +// inline +template +Real atan(const Real & v) +{ + return std::atan(v); +} + +// inline +template +Real atan2(const Real & v, const Real & e) +{ + return std::atan2(v, e); +} + + +// inline +template +Real hypot(const Real & v, const Real & e) +{ + return std::hypot(v, e); +} + +template +Real length(const Real & r) +{ + return abs(r); +} + +template +Real lengthSquared(Real r) +{ + return r*r; +} + +// ---- + +template<> +inline +u128 abs(const u128 &v) +{ + return v; +} + +template<> +inline +s128 abs(const s128 &v) +{ + return v >= 0 ? v : -v; +} + + +template +Real fract(Real r) +{ + Real _; + return std::modf(r, &_); +} + +} // namespace +} // namespace +} // namespace diff --git a/tjp/core/math/RelativeFront+IO.h b/tjp/core/math/RelativeFront+IO.h new file mode 100644 index 0000000..956f277 --- /dev/null +++ b/tjp/core/math/RelativeFront+IO.h @@ -0,0 +1,68 @@ +// +// MathIO.h +// common +// +// Created by Timothy Prepscius on 8/4/18. +// Copyright © 2018 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "RelativeFront.h" +#include "Accuracy+IO.h" + +namespace tjp { +namespace core { +namespace math { + +template +void io_r(IO &io, RelativeFront &a) +{ + auto &v = *a.v; + io.on_vector_begin(v); + + if (!v.empty()) + { + io.on_vector_value(v.front()); + + auto &front = v.front(); + + typedef typename V::value_type VV; + VV vv; + Accuracy avv { &vv, a.m }; + + for (auto i=++v.begin(); i!=v.end(); ++i) + { + io.on_vector_value(avv); + *i = vv + front; + } + } + + io.on_vector_end(v); +} + +template +void io_w(IO &io, const RelativeFront &a) +{ + auto &v = *a.v; + io.on_vector_begin(v); + + if (!v.empty()) + { + auto &front = v.front(); + io.on_vector_value(front); + + for (auto i=++v.begin(); i!=v.end(); ++i) + { + auto vv = *i - front; + io.on_vector_value(with_accuracy(vv, a.m)); + } + } + + io.on_vector_end(v); +} + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/RelativeFront.h b/tjp/core/math/RelativeFront.h new file mode 100644 index 0000000..c6dce37 --- /dev/null +++ b/tjp/core/math/RelativeFront.h @@ -0,0 +1,31 @@ +// +// MathIO.h +// common +// +// Created by Timothy Prepscius on 8/4/18. +// Copyright © 2018 Timothy Prepscius. All rights reserved. +// + +#pragma once + +namespace tjp { +namespace core { +namespace math { + +template +struct RelativeFront +{ + V *v; + Real m; +} ; + +template +auto relative_front(V &v, Real m) +{ + return RelativeFront { &v, m }; +} + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Segment1.h b/tjp/core/math/Segment1.h new file mode 100755 index 0000000..25a94a6 --- /dev/null +++ b/tjp/core/math/Segment1.h @@ -0,0 +1,23 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Real.h" + +namespace tjp { +namespace core { +namespace math { + +template +struct Segment1; + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Segment1.hpp b/tjp/core/math/Segment1.hpp new file mode 100755 index 0000000..0ad4a32 --- /dev/null +++ b/tjp/core/math/Segment1.hpp @@ -0,0 +1,40 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Segment1.h" + +#include "Vector3.hpp" +#include "Vector2.hpp" +#include +#include + +#include "Zero.h" + +namespace tjp { +namespace core { +namespace math { + +template +struct Segment1 +{ + typedef Real value_type; + + Real begin, end; + + static const Segment1 Zero; +} ; + +template +const Segment1 Segment1::Zero = { zero(), zero() }; + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Segment1.inl b/tjp/core/math/Segment1.inl new file mode 100755 index 0000000..92d5dbf --- /dev/null +++ b/tjp/core/math/Segment1.inl @@ -0,0 +1,90 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Segment1.hpp" + +namespace tjp { +namespace core { +namespace math { + +template +auto length(const Segment1 &r) +{ + return distance(r.end,r.begin); +} + +template +auto length_squared(const Segment1 &r) +{ + return distance_squared(r.end,r.begin); +} + +template +bool operator==(const Segment1 &lhs, const Segment1 &rhs) +{ + return lhs.begin == rhs.begin && lhs.end == rhs.end; +} + +template +Segment1 operator +(const Segment1 &lhs, const Segment1 &rhs) +{ + return { + lhs.begin + rhs.begin, + lhs.end + rhs.end + }; +} + +template +Segment1 operator -(const Segment1 &lhs, const Segment1 &rhs) +{ + return { + lhs.begin - rhs.begin, + lhs.end - rhs.end + }; +} + +template +Segment1 operator /(const Segment1 &lhs, const size_t &rhs) +{ + return { + (Real)(lhs.begin / rhs), + (Real)(lhs.end / rhs) + }; +} + + +template +auto distance(const Segment1 &s0, const Segment1 &s1) +{ + return distance((s0.begin+s0.end),(s1.begin+s1.end)) - (length(s0) + length(s1)); +} + +template +auto distance_squared(const Segment1 &s0, const Segment1 &s1) +{ + return distance_squared((s0.begin+s0.end),(s1.begin+s1.end)) - (length_squared(s0) + length_squared(s1)); +} + +template +auto distance_relative(const Segment1 &s0, const Segment1 &s1) +{ + return distance(s0, s1); +} + +template +void zero(Segment1 &v) +{ + v = Segment1::Zero; +} + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/SimpleLine.cpp b/tjp/core/math/SimpleLine.cpp new file mode 100755 index 0000000..c2ea26a --- /dev/null +++ b/tjp/core/math/SimpleLine.cpp @@ -0,0 +1,62 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#include "SimpleLine.hpp" + +#include "Vector2.inl" +#include + +namespace tjp::core::math { + +SimpleLineCompute::SimpleLineCompute(std::initializer_list l, bool cap_) : + cap(cap_) +{ + p.insert(p.end(), l.begin(), l.end()); + s.resize(p.size()-1); + + if (p.empty()) + return ; + + auto next = p.begin(); + auto prev = next++; + auto write = s.begin(); + for ( ;next!=p.end(); prev = next++) + { + auto d = *next - *prev; + debug_assert(d[0] != 0); + + auto sv = d[1]/d[0]; + *write++ = sv; + } +} + +float SimpleLineCompute::operator ()(float x) +{ + debug_assert(!p.empty()); + + if (cap && x < p.front().x()) + return p.front().y(); + + auto last = p.size()-1; + for (auto i=1; ; ++i) + { + auto &r = p[i]; + if (x < r.x() || i == last) + { + if (i == last && cap) + return p[i].y(); + + auto &l = p[i-1]; + auto &s_ = s[i-1]; + return l.y() + (x-l.x()) * s_; + } + } +} + +} // namespace + diff --git a/tjp/core/math/SimpleLine.h b/tjp/core/math/SimpleLine.h new file mode 100755 index 0000000..3de0806 --- /dev/null +++ b/tjp/core/math/SimpleLine.h @@ -0,0 +1,20 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +namespace tjp { +namespace core { +namespace math { + +struct SimpleLineCompute; + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/SimpleLine.hpp b/tjp/core/math/SimpleLine.hpp new file mode 100755 index 0000000..6f50aa3 --- /dev/null +++ b/tjp/core/math/SimpleLine.hpp @@ -0,0 +1,34 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#include "Vector2.hpp" +#include + +#pragma once + +namespace tjp { +namespace core { +namespace math { + +struct SimpleLineCompute +{ + core::Vector p; + core::Vector s; + bool cap; + + SimpleLineCompute( + std::initializer_list l, + bool cap + ); + float operator ()(float x); +} ; + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Sphere1.h b/tjp/core/math/Sphere1.h new file mode 100755 index 0000000..90babc9 --- /dev/null +++ b/tjp/core/math/Sphere1.h @@ -0,0 +1,24 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +namespace tjp { +namespace core { +namespace math { + +template +class Sphere1; + +typedef Sphere1 Sphere1i64; +typedef Sphere1 Sphere1i128; + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Sphere1.hpp b/tjp/core/math/Sphere1.hpp new file mode 100755 index 0000000..9e1c19c --- /dev/null +++ b/tjp/core/math/Sphere1.hpp @@ -0,0 +1,64 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Sphere1.h" + +#include "Zero.h" +#include +#include + +namespace tjp { +namespace core { +namespace math { + +template +class Sphere1 +{ +public: + typedef Real value_type; + typedef D Distance; + typedef C Center; + + typedef Sphere1 Self; + + Center center; + Distance radius; + + Sphere1 () {} + Sphere1 (Center center_, Distance radius_) : + center(center_), + radius(radius_) + { + } + + const static Self Zero; + const static Self Infinite; + + Distance distanceTo(Real p) const; + Distance minDistanceTo (const Self &v) const; + Distance maxDistanceTo (const Self &v) const; + + Distance minDistanceTo (Real v) const; + Distance maxDistanceTo (Real v) const; +} ; + +template +const Sphere1 Sphere1::Zero = { zero
(), zero() }; + +template +const Sphere1 Sphere1::Infinite = { zero
(), std::numeric_limits::infinity() }; + +typedef Sphere1 Sphere1i64; +typedef Sphere1 Sphere1i128; + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Sphere1.inl b/tjp/core/math/Sphere1.inl new file mode 100755 index 0000000..87bffe3 --- /dev/null +++ b/tjp/core/math/Sphere1.inl @@ -0,0 +1,117 @@ +// +// Math.inl +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Zero.h" +#include "Sphere1.hpp" + +namespace tjp { +namespace core { +namespace math { + +template +D Sphere1::distanceTo (Real p) const +{ + return (p - center) - radius; +} + +// inline +template +D Sphere1::minDistanceTo (const Self &p) const +{ + return distance(p.center, center) - (radius + p.radius); +} + +template +D Sphere1::maxDistanceTo (const Self & p) const +{ + auto centerDistance = (p.center - center); + auto diffRadius = std::abs(p.radius - radius); + + // if the circle is within the other + if (diffRadius > centerDistance) + return diffRadius - centerDistance; + + // if the circle is not within the other + auto sumRadius = p.radius + radius; + return centerDistance + sumRadius; +} + +template +bool operator ==(const Sphere1 &l, const Sphere1 &r) +{ + return l.center == r.center && l.radius == r.radius; +} + +template +D distance (const Sphere1 &lhs, const Sphere1 &rhs) +{ + return distance(lhs.center, rhs.center) - (lhs.radius + rhs.radius); +} + +template +D distance_squared (const Sphere1 &lhs, const Sphere1 &rhs) +{ + return distance_squared(lhs.center, rhs.center) - pow2(lhs.radius + rhs.radius); +} + +template +D distance_relative(const Sphere1 &l, const Sphere1 &r) +{ + return distance_squared(l, r); +} + +template +Sphere1 operator+(const Sphere1 &lhs, const Sphere1 &rhs) +{ + return { + lhs.center + rhs.center, + lhs.radius + rhs.radius + }; +} + +template +Sphere1 operator-(const Sphere1 &lhs, const Sphere1 &rhs) +{ + return { + lhs.center - rhs.center, + lhs.radius - rhs.radius + }; +} + +template +Sphere1 operator /(const Sphere1 &lhs, const D &rhs) +{ + return { + lhs.center / rhs, + lhs.radius / rhs + }; +} + +template +Sphere1 operator /(const Sphere1 &lhs, size_t rhs) +{ + return { + lhs.center / rhs, + lhs.radius / rhs + }; +} + +template +void zero(Sphere1 &v) +{ + v = { + zero(), + zero() + }; +} + +} // namespace +} // namespace +} // namespace diff --git a/tjp/core/math/Sphere3.cpp b/tjp/core/math/Sphere3.cpp new file mode 100755 index 0000000..44eb2b3 --- /dev/null +++ b/tjp/core/math/Sphere3.cpp @@ -0,0 +1,43 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#include "Sphere3.hpp" +#include "GTE_convert.hpp" + +#define GTE_NO_LOGGER +#include +#include + + +namespace tjp { +namespace core { +namespace math { + + +Sphere3r minimumBoundingSphere(const Vector &translates_) +{ + if (translates_.empty()) + return Sphere3r::Zero; + + std::vector> translates; + + for (auto &p : translates_) + translates.push_back(gte_c(p)); + + gte::Sphere3 sphere; + gte::MinimumVolumeSphere3 generator; + generator(static_cast(translates.size()), translates.data(), sphere); + + return gte_c(sphere); +} + + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Sphere3.h b/tjp/core/math/Sphere3.h new file mode 100755 index 0000000..90388b9 --- /dev/null +++ b/tjp/core/math/Sphere3.h @@ -0,0 +1,27 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Real.h" + +namespace tjp { +namespace core { +namespace math { + +template +class Sphere3; + +typedef Sphere3 Sphere3f; +typedef Sphere3 Sphere3d; +typedef Sphere3 Sphere3r; + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Sphere3.hpp b/tjp/core/math/Sphere3.hpp new file mode 100755 index 0000000..b6b6d96 --- /dev/null +++ b/tjp/core/math/Sphere3.hpp @@ -0,0 +1,78 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Sphere3.h" + +#include "Zero.h" +#include +#include + +#include "Vector3.hpp" +#include + +namespace tjp { +namespace core { +namespace math { + +template +class Sphere3 +{ +public: + typedef Real value_type; + + typedef Vector3 Center; + Center center; + Real radius; + + Sphere3 () {} + + Sphere3 (const Vector3 ¢er_, Real radius_) : + center(center_), + radius(radius_) + { + } + + Real distanceTo(const Vector3 &p) const; + Real minDistanceTo (const Sphere3 &v) const; + Real maxDistanceTo (const Sphere3 &v) const; + + Real minDistanceTo (const Vector3 &v) const; + Real maxDistanceTo (const Vector3 &v) const; + + bool contains(const Vector3 &p) const; + bool contains(const Sphere3 &v) const; + + const static Sphere3 Zero; + const static Sphere3 Infinite; + + template + Sphere3 asType() const + { + return Sphere3 { center.template asType(), T(radius) }; + } +}; + +template +const Sphere3 Sphere3::Zero = { Vector3::Zero, 0 }; + +template +const Sphere3 Sphere3::Infinite = { Vector3::Zero, std::numeric_limits::infinity() }; + +typedef Sphere3 Sphere3f; +typedef Sphere3 Sphere3d; +typedef Sphere3 Sphere3r; + +Sphere3r minimumBoundingSphere(const Vector &points); + + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Sphere3.inl b/tjp/core/math/Sphere3.inl new file mode 100755 index 0000000..5850339 --- /dev/null +++ b/tjp/core/math/Sphere3.inl @@ -0,0 +1,197 @@ +// +// Math.inl +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// +#pragma once + +#include "Sphere3.hpp" +#include "Real.hpp" +#include "Vector3.inl" +#include "Zero.h" + +namespace tjp { +namespace core { +namespace math { + +template +bool operator==(const Sphere3& lhs, const Sphere3& rhs) +{ + return lhs.center == rhs.center && lhs.radius == rhs.radius; +} + +template +bool operator!=(const Sphere3& lhs, const Sphere3& rhs) +{ + return !(lhs == rhs); +} + +// inline +template +Real Sphere3::distanceTo (const Vector3& p) const +{ + return distance(p, center) - radius; +} + +// inline +template +Real Sphere3::minDistanceTo (const Sphere3& p) const +{ + return distance(p.center, center) - (radius + p.radius); +} + +// inline +template +Real Sphere3::maxDistanceTo (const Sphere3& p) const +{ + auto centerDistance = distance(p.center, center); + auto diffRadius = std::abs(p.radius - radius); + + // if the circle is within the other + if (diffRadius > centerDistance) + return diffRadius - centerDistance; + + // if the circle is not within the other + auto sumRadius = p.radius + radius; + return centerDistance + sumRadius; +} + +template +Real Sphere3::minDistanceTo (const Vector3& p) const +{ + return (p - center).length() - radius; +} + +template +Real Sphere3::maxDistanceTo (const Vector3& p) const +{ + auto distance = (p - center).length(); + + if (radius > distance) + return distance - radius; + + return distance + radius; +} + +template +Real distance(const Sphere3 &l, const Sphere3 &r) +{ + return distance(l.center, r.center) - (l.radius + r.radius); +} + +template +Real distance(const Sphere3 &l, const Vector3 &r) +{ + return distance(l.center, r) - (l.radius); +} + +// + +template +Real distance_squared_exact(const Sphere3 &l, const Sphere3 &r) +{ + return pow2(distance(l, r)); +} + +template +Real distance_squared_approx(const Sphere3 &l, const Sphere3 &r) +{ + return distance_squared(l.center, r.center) - math::pow2(l.radius + r.radius); +} + +template +Real distance_squared(const Sphere3 &l, const Vector3 &r) +{ + return distance_squared(l.center, r) - math::pow2(l.radius); +} + +template +Real distance_relative(const Sphere3 &l, const Sphere3 &r) +{ + return distance_squared_approx(l, r); +} + +// inline +template +bool Sphere3::contains (const Vector3& p) const +{ + auto radiusSquared = radius * radius; + return (p - center).lengthSquared() < radiusSquared; +} + +template +bool Sphere3::contains (const Sphere3& v) const +{ + auto r = (radius - v.radius); + auto r2 = r * r; + return (v.center - center).lengthSquared() < r2; +} + + +template +bool same(const Sphere3 &lhs, const Sphere3 &rhs, Real epsilon) +{ + if ((lhs.center - rhs.center).length() > epsilon) + return false; + + if (std::abs(lhs.radius - rhs.radius) > epsilon) + return false; + + return true; +} + +template +void zero(Sphere3 &r) +{ + r = { + zero::Center>(), + zero() + } ; +} + +template +Sphere3 &operator +=(Sphere3 &lhs, const Sphere3 &rhs) +{ + lhs.center += rhs.center; + lhs.radius += rhs.radius; + + return lhs; +} + +template +Sphere3 operator +(const Sphere3 &lhs, const Sphere3 &rhs) +{ + return { lhs.center+rhs.center, lhs.radius+rhs.radius }; +} + +template +Sphere3 operator -(const Sphere3 &lhs, const Sphere3 &rhs) +{ + return { lhs.center-rhs.center, lhs.radius-rhs.radius }; +} + +template +Sphere3 operator /(const Sphere3 &lhs, const U &rhs) +{ + return Sphere3 { + lhs.center / rhs, + lhs.radius / rhs + }; +} + +template +Sphere3 operator *(const U &lhs, const Sphere3 &rhs) +{ + return Sphere3 { + lhs * rhs.center, + lhs * rhs.radius + }; +} + + + +} // namespace +} // namespace +} // namespace diff --git a/tjp/core/math/Statistics.h b/tjp/core/math/Statistics.h new file mode 100755 index 0000000..18c8a52 --- /dev/null +++ b/tjp/core/math/Statistics.h @@ -0,0 +1,665 @@ +// +// Server.hpp +// TimeSync +// +// Created by Timothy Prepscius on 1/27/17. +// Copyright © 2017 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace tjp { +namespace core { +namespace math { + +struct RunningStatsWeightedAverager +{ + typedef double T; + double weight, oneMinusWeight; + T m, s; + bool initialized = false; + + RunningStatsWeightedAverager(double weight_ = 0.8) : + m(0), + s(0), + weight(weight_), + oneMinusWeight(1.0 - weight_) + { + clear(); + } + + void clear() + { + m = 0; + s = 0; + } + + void initialize(T x) + { + m = x; + initialized = true; + } + + void push(T x) + { + if (!initialized) + initialize(x); + + // See Knuth TAOCP vol 2, 3rd edition, page 232 + auto newM = weight * m + oneMinusWeight * x; + auto newS = weight * s + oneMinusWeight * std::abs(x - m); + + // set up for next iteration + m = newM; + s = newS; + } + + double mean() const + { + return m; + } + + double error() const + { + return s; + } + +}; + +template +class RunningStats +{ +public: + RunningStats() + { + clear(); + } + + void clear() + { + n = 0; + m = 0; + s = 0; + } + + void push(T x) + { + n++; + + // See Knuth TAOCP vol 2, 3rd edition, page 232 + auto newM = m + (x - m) / n; + auto newS = s + (x - m)*(x - newM); + + // set up for next iteration + m = newM; + s = newS; + } + + int numDataValues() const + { + return n; + } + + double mean() const + { + return (n > 0) ? m : 0.0; + } + + double variance() const + { + return ((n > 1) ? s / (n - 1) : 0.0); + } + + double standardDeviation() const + { + return std::sqrt(variance()); + } + +private: + int n; + T m, s; +}; + +template +class AccumulatedStats +{ +protected: + std::vector samples; + + T unresolved; + T m; + T e; + + void calculate() + { + m = e = unresolved; + + if (samples.empty()) + return; + + T s = 0; + for (auto &t : samples) + { + s += t; + } + + m = s /= samples.size(); + + if (samples.size() < 2) + return; + + T s0 = 0; + for (int i = 0; i < samples.size() / 2; ++i) + { + s0 += samples[i]; + } + + T s1 = 0; + for (int i = samples.size() / 2; i < samples.size(); ++i) + { + s1 += samples[i]; + } + + s0 /= samples.size() / 2; + s1 /= samples.size() - samples.size() / 2; + + e = s1 - s0; + } + +public: + AccumulatedStats(T unresolved) + { + this->unresolved = unresolved; + } + + void push(T t) + { + samples.push_back(t); + calculate(); + } + + void clear() + { + samples.clear(); + calculate(); + } + + T mean() + { + return m; + } + + T error() + { + return e; + } + + T errorSize() + { + return std::abs(e); + } +}; + +template +R valueOf(const T &t) { return (R)t; } + +template +R weightOf(const T &t) { return (R)1.0; } + +template +double stdev_lengthSquared(const T &d) +{ + return (double)d * (double)d; +} + +template +T zero_of() +{ + return (T)0.0; +} + +template +R mean(const V &v, std::function f=valueOf) +{ + R sum = zero_of(); + for (auto &t : v) + { + sum += f(t); + } + + auto mean = sum / v.size(); + return mean; +} + +template +R weighted_mean(const V &v, + std::function f=valueOf, + std::function w=weightOf +) +{ + R sum = zero_of(); + R weight = zero_of(); + for (auto &t : v) + { + auto w_ = w(t); + sum += w_ * f(t); + weight += w_; + } + + auto mean = sum / weight; + return mean; +} + +template +double stdev(const V &v, const R &mean, std::function f=valueOf) +{ + double sum = zero_of(); + for (auto &t : v) + { + auto diff = f(t) - mean; + sum += stdev_lengthSquared(diff); + } + + return std::sqrt(sum / (double)v.size()); +} + +template +double stdev(const V &v, std::function f=valueOf) +{ + typedef typename V::value_type T; + T mean = math::mean(v, f); + return stdev(v, mean); +} + +template +struct MeanStddev +{ + T mean; + T stddev; +} ; + +template +MeanStddev rejectOutliersMeanStddev(const V &samples, R a, std::function f=valueOf) +{ + R m, e; + + auto u = math::mean(samples); + auto s = math::stdev(samples); + + // filtered = [e for e in data_bad if (u - 2 * s < e < u + 2 * s)] + std::vector filtered; + for (auto &v : samples) + { + if (u - a * s < v && v < u + a * s) + { + filtered.push_back(v); + } + } + + if (filtered.empty()) + { + m = e = 0; + return { m, e }; + } + + return { math::mean(filtered), math::stdev(filtered) }; +} + +template +class RejectOutlierStats +{ +protected: + std::vector samples; + + double a; + T unresolved; + T m; + T e; + + void calculate() + { + if (samples.empty()) + { + m = e = unresolved; + return; + } + + auto u = math::mean(samples); + auto s = math::stdev(samples); + + // filtered = [e for e in data_bad if (u - 2 * s < e < u + 2 * s)] + std::vector filtered; + for (auto &v : samples) + { + if (u - a * s < v && v < u + a * s) + { + filtered.push_back(v); + } + } + + if (filtered.empty()) + { + m = e = unresolved; + return; + } + + auto m = math::mean(filtered); + auto e = math::stdev(filtered); + + this->m = m; + this->e = e; + } + +public: + RejectOutlierStats(T unresolved, double a = 2.0) + { + this->unresolved = unresolved; + m = e = unresolved; + this->a = a; + } + + void push(T t) + { + samples.push_back(t); + calculate(); + } + + void clear() + { + samples.clear(); + calculate(); + } + + T mean() + { + return m; + } + + T error() + { + return e; + } + + T errorSize() + { + return std::abs(e); + } + + size_t size () const + { + return samples.size(); + } +}; + +template +class WindowStats +{ +protected: + std::deque samples; + + int windowSize; + double a; + T unresolved; + T m; + T e; + T l; + + void calculate() + { + m = e = l = unresolved; + + if (samples.empty()) + return; + + auto &window = samples; + + typedef double R; + m = math::mean(window); + e = math::stdev(window); + } + +public: + WindowStats(T unresolved, int windowSize, double a = 2.0) + { + this->unresolved = unresolved; + l = m = e = unresolved; + this->a = a; + this->windowSize = windowSize; + } + + void push(T t) + { + samples.push_front(t); + while (samples.size() > windowSize) + samples.pop_back(); + + calculate(); + } + + void clear() + { + samples.clear(); + calculate(); + } + + T mean() + { + return m; + } + + T min() + { + return l; + } + + T error() + { + return e; + } + + T errorSize() + { + return std::abs(e); + } +}; + +template +class RejectOutlierWindowStats +{ +protected: + std::deque samples; + + int windowSize; + double a; + T unresolved; + T m; + T e; + T l; + + void calculate() + { + m = e = l = unresolved; + + if (samples.empty()) + return; + + auto &window = samples; + + typedef double R; + R u = math::mean(window); + R s = math::stdev(window); + + // filtered = [e for e in data_bad if (u - 2 * s < e < u + 2 * s)] + std::vector filtered; + for (auto &v : window) + { + if (l == unresolved) + l = v; + else + l = std::min(l, v); + + if (u - a * s < v && v < u + a * s) + { + filtered.push_back(v); + } + } + + if (filtered.empty()) + return; + + m = math::mean(filtered); + + e = math::stdev(filtered); + } + +public: + RejectOutlierWindowStats(T unresolved, int windowSize, double a = 2.0) + { + this->unresolved = unresolved; + l = m = e = unresolved; + this->a = a; + this->windowSize = windowSize; + } + + void push(T t) + { + samples.push_back(t); + if (samples.size() > windowSize) + samples.pop_front(); + + calculate(); + } + + void clear() + { + samples.clear(); + calculate(); + } + + T mean() + { + return m; + } + + T min() + { + return l; + } + + T error() + { + return e; + } + + T errorSize() + { + return std::abs(e); + } +}; + + +template +class RejectOutlierUseBestStatsWindow +{ +protected: + typedef std::pair Sample; + std::vector samples; + int numSamplesToReduce; + int numSamplesToInclude; + + double a; + T unresolved; + T m; + T e; + + void calculate() + { + m = e = unresolved; + + if (samples.empty()) + return; + + auto numSamplesToReduce = std::min((int)samples.size(), this->numSamplesToReduce == -1 ? INT_MAX : this->numSamplesToReduce); + std::vector last(samples.end() - numSamplesToReduce, samples.end()); + + std::sort(last.begin(), last.end(), [](Sample &l, Sample &r) { return l.second < r.second; }); + auto numSamplesToInclude = std::min((int)last.size(), this->numSamplesToInclude); + + std::vector best; + for (auto i = 0; i < numSamplesToInclude; ++i) + { + best.push_back(last[i].first); + } + + double u = math::mean(best); + double s = math::stdev(best); + + // filtered = [e for e in data_bad if (u - 2 * s < e < u + 2 * s)] + std::vector filtered; + for (auto &v : best) + { + if (u - a * s < v && v < u + a * s) + { + filtered.push_back(v); + } + } + + if (filtered.empty()) + return; + + m = math::mean(filtered); + e = math::stdev(filtered); + } + +public: + RejectOutlierUseBestStatsWindow(T unresolved, int numSamplesToReduce, int numSamplesToInclude, double a = 2.0) + { + this->unresolved = unresolved; + m = e = unresolved; + this->a = a; + + this->numSamplesToReduce = numSamplesToReduce; + this->numSamplesToInclude = numSamplesToInclude; + } + + void push(T t, R r) + { + samples.push_back({ t, r }); + calculate(); + } + + void clear() + { + samples.clear(); + calculate(); + } + + T mean() + { + return m; + } + + T error() + { + return e; + } + + T errorSize() + { + return std::abs(e); + } +}; + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Vector2.h b/tjp/core/math/Vector2.h new file mode 100755 index 0000000..05bf1d5 --- /dev/null +++ b/tjp/core/math/Vector2.h @@ -0,0 +1,36 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Real.h" + +namespace tjp { +namespace core { +namespace math { + +template +struct Vector2_; + +typedef Vector2_ Vector2d_; +typedef Vector2_ Vector2f_; +typedef Vector2_ Vector2r_; +typedef Vector2_ Vector2i_; + +template +struct Vector2; + +typedef Vector2 Vector2d; +typedef Vector2 Vector2f; +typedef Vector2 Vector2r; +typedef Vector2 Vector2i; + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Vector2.hpp b/tjp/core/math/Vector2.hpp new file mode 100755 index 0000000..35efe70 --- /dev/null +++ b/tjp/core/math/Vector2.hpp @@ -0,0 +1,125 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Vector2.h" +#include "Zero.h" +#include + +#include + +namespace tjp::core::math { + +template +struct Vector2_ { + using V = Real[2]; + V v; + + Real &operator[](size_t i) { return v[i]; } + Real const &operator[](size_t i) const { return v[i]; }; +} ; + + +template +struct Vector2 +{ + using Real = T; + using V = Vector2_; + V v; + + constexpr Vector2(int zero) : + v { (T)zero, (T)zero } + {} + + constexpr Vector2() = default; + constexpr Vector2(const Vector2 &) = default; + constexpr Vector2(const V &rhs) : v (rhs) {} + constexpr Vector2(const std::initializer_list &v_) + { + auto i = 0; + for (auto &n: v_) + v[i++] = n; + } + + constexpr Vector2& operator=(const Vector2 &) = default; + constexpr Vector2& operator=(const V &v_) + { + v = v_; + return *this; + } + + constexpr Vector2& operator=(const std::initializer_list &v_) + { + auto i = 0; + for (auto &n: v_) + v[i++] = n; + + return *this; + } + + constexpr Vector2(Real x, Real y) + : v {x, y} + {} + + operator V &() { return v; } + operator const V &() const { return v; } + + T &x() { return v[0]; } + T &y() { return v[1]; } + + const T &x() const { return v[0]; } + const T &y() const { return v[1]; } + + template + Vector2 asType() const; + + T lengthSquared () const; + T length () const; + + template + Vector2 normalize() const; + + T &operator[](size_t i); + const T &operator[](size_t i) const; + + void flip (); + + static const Vector2 Zero; +} ; + +template +const Vector2 Vector2::Zero = { zero(),zero() }; + + +template +Real &Vector2::operator[](size_t i) +{ + return v[i]; +} + +template +const Real &Vector2::operator[](size_t i) const +{ + return v[i]; +} + +template +template +Vector2 Vector2::asType() const +{ + return Vector2 { (U)x(), (U)y() }; +} + +typedef Vector2 Vector2d; +typedef Vector2 Vector2f; +typedef Vector2 Vector2r; +typedef Vector2 Vector2i; + +} // namespace + diff --git a/tjp/core/math/Vector2.inl b/tjp/core/math/Vector2.inl new file mode 100755 index 0000000..8e196c9 --- /dev/null +++ b/tjp/core/math/Vector2.inl @@ -0,0 +1,241 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Vector2.hpp" + +#include "Real.h" +#include "Real.inl" + +#include +#include +#include "Zero.h" + +namespace tjp { +namespace core { +namespace math { + +template +void zero(Vector2 &v) +{ + v = Vector2::Zero; +} + +template +Vector2 abs(const Vector2 &v) +{ + return { abs(v[0]), abs(v[1]) }; +} + +template +Real lengthSquared(const Vector2 &r) +{ + return r.lengthSquared(); +} + +template +Real length(const Vector2 &r) +{ + return r.length(); +} + +template +Real Vector2::lengthSquared () const +{ + Real x = v[0]; + Real y = v[1]; + return x*x + y*y; +} + +template +Real Vector2::length () const +{ + return sqrt(lengthSquared()); +} + +template +template +Vector2 Vector2::normalize() const +{ + auto l = length(); + if (l == 0) + return { D(0), D(0) }; + + return *this / l; +} + +template +void Vector2::flip () +{ + std::swap(v[0], v[1]); +} + +template +Real dot(Vector2 const& l, Vector2 const& r) +{ + return l[0] * r[0] + l[1] * r[1]; +} + +template +Vector2 operator *(Real m, Vector2 const& r) +{ + return { m * r[0], m * r[1] }; +} + +template +Vector2 operator *(Vector2 const& r, Real m) +{ + return { m * r[0], m * r[1] }; +} + +template +Vector2 operator /(U m, Vector2 const& r) +{ + return { m / r[0], m / r[1] }; +} + + +template +Vector2 operator -(const Vector2 &v) +{ + return { -v[0], -v[1] }; +} + +template +Vector2 &operator +=(Vector2 &v, const Vector2 &r) +{ + v[0] += r[0]; + v[1] += r[1]; + + return v; +} + +template +Vector2 &operator -=(Vector2 &v, const Vector2 &r) +{ + v[0] -= r[1]; + v[0] -= r[1]; + + return v; +} + +template +Vector2 &operator /=(Vector2 &v, Real r) +{ + v[0] /= r; + v[1] /= r; + + return v; +} + +template +Vector2 &operator *=(Vector2 &v, Real r) +{ + v[0] *= r; + v[1] *= r; + + return v; +} + +template +Vector2_ operator -(const Vector2_ &l, const Vector2_ &r) +{ + return { l[0] - r[0], l[1] - r[1] }; +} + +template +Vector2 operator -(const Vector2 &l, const Vector2 &r) +{ + return Vector2(l.v - r.v); +} + +template +Vector2 operator +(const Vector2 &l, const Vector2 &r) +{ + return { l[0] + r[0], l[1] + r[1] }; +} + +template +Vector2 operator /(const Vector2 &p, const X &m) +{ + return { T(p[0]/m), T(p[1]/m) }; +} + +template +Vector2 cross(const Vector2 &l, const Vector2 &r); + +template +Vector2 multiply(const Vector2 &l, const Vector2 &r) +{ + return { l[0] * r[0], l[1] * r[1] }; +} + +template +Vector2 mul(const Vector2 &l, const Vector2 &r) +{ + return multiply(l, r); +} + +template +Vector2 divide(const Vector2 &l, const Vector2 &r) +{ + return { l[0] / r[0], l[1] / r[1] }; +} + +template +Vector2 operator /(const Vector2 &l, const Vector2 &r) +{ + return { l[0] / r[0], l[1] / r[1] }; +} + +template +bool operator !=(const Vector2_ &l, const Vector2_ &r) +{ + return + l[0] != r[0] || + l[1] != r[1]; +} + + +template +bool operator ==(const Vector2_ &l, const Vector2_ &r) +{ + return + l[0] == r[0] && + l[1] == r[1]; +} + +template +bool operator !=(const Vector2 &l, const Vector2 &r) { return l.v != r.v; } + +template +bool operator ==(const Vector2 &l, const Vector2 &r) { return l.v == r.v; } + +template +Vector2 fract(const Vector2 &v) +{ + return { + fract(v[0]), + fract(v[1]) + }; +} + +template +Vector2 trunc(const Vector2 &v) +{ + return { + trunc(v[0]), + trunc(v[1]) + }; +} + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Vector3.h b/tjp/core/math/Vector3.h new file mode 100755 index 0000000..de95a60 --- /dev/null +++ b/tjp/core/math/Vector3.h @@ -0,0 +1,35 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Real.h" + +namespace tjp { +namespace core { +namespace math { + +template +struct Vector3_; + +typedef Vector3_ Vector3d_; +typedef Vector3_ Vector3f_; +typedef Vector3_ Vector3r_; + +template +struct Vector3; + +typedef Vector3 Vector3d; +typedef Vector3 Vector3f; +typedef Vector3 Vector3r; + + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Vector3.hpp b/tjp/core/math/Vector3.hpp new file mode 100755 index 0000000..335f336 --- /dev/null +++ b/tjp/core/math/Vector3.hpp @@ -0,0 +1,118 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Vector3.h" +#include "Zero.h" +#include +#include + +#include +#include + +namespace tjp { +namespace core { +namespace math { + +template +struct Vector3_ { + using V = Real[3]; + V v; + + Real &operator[](size_t i) { return v[i]; } + Real const &operator[](size_t i) const { return v[i]; }; +} ; + +template +struct Vector3 +{ + using Real = T; + using V = Vector3_; + V v; + + constexpr Vector3(int zero) : + v { static_cast(zero), static_cast(zero), static_cast(zero) } + {} + + constexpr Vector3() = default; + constexpr Vector3(const Vector3 &) = default; + constexpr Vector3(const V &rhs) : v (rhs) {} + constexpr Vector3(const std::initializer_list &v_) + { + auto i = 0; + for (auto &n: v_) + v[i++] = n; + } + + constexpr Vector3& operator=(const Vector3 &) = default; + constexpr Vector3& operator=(const V &v_) + { + v = v_; + return *this; + } + + constexpr Vector3(Real x, Real y, Real z) + : v {x, y, z} + {} + + operator V() + { + return { v[0], v[1], v[2] }; + } + + Real length () const; + Real lengthSquared () const; + Vector3 normalize () const; + + Vector3 operator -() const; + Vector3 &operator +=(const Vector3 &r); + Vector3 &operator -=(const Vector3 &r); + + Vector3 &operator /=(Real r); + Vector3 &operator *=(Real r); + + Real &operator[](size_t size); + Real const &operator[](size_t size) const; + + template + Vector3 asType() const; + + static const Vector3 Zero; +} ; + +template +const Vector3 Vector3::Zero = { zero(),zero(),zero() }; + +template +Real &Vector3::operator[](size_t size) +{ + return v[size]; +} + +template +Real const &Vector3::operator[](size_t size) const +{ + return v[size]; +} + +template +template +Vector3 Vector3::asType() const +{ + return Vector3 { (U)v[0], (U)v[1], (U)v[2] }; +} + +typedef Vector3 Vector3d; +typedef Vector3 Vector3f; +typedef Vector3 Vector3r; + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Vector3.inl b/tjp/core/math/Vector3.inl new file mode 100755 index 0000000..7ba45ed --- /dev/null +++ b/tjp/core/math/Vector3.inl @@ -0,0 +1,285 @@ +// +// Math.inl +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Vector3.hpp" +#include "Zero.h" + +namespace tjp { +namespace core { +namespace math { + +template +Real lengthSquared(const Vector3 &r) +{ + return r.lengthSquared(); +} + + +template +Real length(const Vector3 &r) +{ + return r.length(); +} + +template +void zero(Vector3 &v) +{ + v = Vector3::Zero; +} + +// inline +template +Real Vector3::length () const +{ + return sqrt(lengthSquared()); +} + +// inline +template +Real Vector3::lengthSquared() const +{ + return v[0] * v[0] + v[1] * v[1] + v[2] * v[2]; +} + +// inline +template +Vector3 Vector3::normalize () const +{ + return *this / length(); +} + +// inline +template +Vector3 operator *(const Vector3 &l, U r) +{ + return Vector3 { + l[0] * r, + l[1] * r, + l[2] * r + }; +} + +template +Vector3 mul(const Vector3 &l, const Vector3 &r) +{ + return { l[0] * r[0], l[1] * r[1], l[2] * r[2]}; +} + +// inline +template +Vector3 operator /(const Vector3 &l, U r) +{ + return Vector3 { + l[0] / r, + l[1] / r, + l[2] / r + }; +} + +// inline +template +Vector3 operator *(U l, const Vector3 &r) +{ + return r * l; +} + +// inline +template +Vector3 operator /(U l, const Vector3 &r) +{ + return Vector3 { + l / r[0], + l / r[1], + l / r[2] + }; +} + +template +Vector3 div(const Vector3 &l, const Vector3 &r) +{ + return { l[0] / r[0], l[1] / r[1], l[2] / r[2] }; +} + +// inline +template +Vector3 Vector3::operator -() const +{ + return { -v[0], -v[1], -v[2] }; +} + +// inline +template +Vector3_ operator +(const Vector3_ &l, const Vector3_ &r) +{ + return { l[0] + r[0], l[1] + r[1], l[2] + r[2] }; +} + +// inline +template +Vector3 operator +(const Vector3 &l, const Vector3 &r) +{ + return l.v + r.v; +} + +template +Vector3_ operator -(const Vector3_ &l, const Vector3_ &r) +{ + return { l[0] - r[0], l[1] - r[1], l[2] - r[2] }; +} + +// inline +template +Vector3 operator -(const Vector3 &l, const Vector3 &r) +{ + return l.v - r.v; +} + +// inline +template +Vector3 &Vector3::operator +=(const Vector3 &r) +{ + v[0] += r.v[0]; + v[1] += r.v[1]; + v[2] += r.v[2]; + + return *this; +} + +// inline +template +Vector3 &Vector3::operator -=(const Vector3 &r) +{ + v[0] -= r.v[0]; + v[1] -= r.v[1]; + v[2] -= r.v[2]; + + return *this; +} + +// inline +template +Vector3 &Vector3::operator /=(Real r) +{ + v[0] /= r; + v[1] /= r; + v[2] /= r; + + return *this; +} + +// inline +template +Vector3 &Vector3::operator *=(Real r) +{ + v[0] *= r; + v[1] *= r; + v[2] *= r; + + return *this; +} + +// inline +template +Real dot(Vector3 const& l, Vector3 const& r) +{ + return l[0] * r[0] + l[1] * r[1] + l[2] * r[2]; +} + +// inline +template +Vector3 cross(Vector3 const& v0, Vector3 const& v1) +{ + Vector3 result = Vector3::Zero; + result[0] = v0[1] * v1[2] - v0[2] * v1[1]; + result[1] = v0[2] * v1[0] - v0[0] * v1[2]; + result[2] = v0[0] * v1[1] - v0[1] * v1[0]; + return result; +} + +// inline +template +Vector3 operator ^(Vector3 const& v0, Vector3 const& v1) +{ + return cross(v0, v1); +} + +template +bool operator ==(const Vector3_ &l, const Vector3_ &r) +{ + return + l[0] == r[0] && + l[1] == r[1] && + l[2] == r[2]; +} + +template +bool operator !=(const Vector3_ &l, const Vector3_ &r) +{ + return + l[0] != r[0] || + l[1] != r[1] || + l[2] != r[2]; +} + +template +bool operator !=(const Vector3 &l, const Vector3 &r) { return l.v != r.v; } + +template +bool operator ==(const Vector3 &l, const Vector3 &r) { return l.v == r.v; } + +template +bool operator<(const Vector3 &l, const Vector3 &r) +{ + if (l[0] < r[0]) return true; + if (l[0] > r[0]) return false; + if (l[1] < r[1]) return true; + if (l[1] > r[1]) return false; + if (l[2] < r[2]) return true; + + return false; +} + +// inline +template +Real operator *(const Vector3 &l, const Vector3 &r) +{ + return dot(l, r); +} + +template +Vector3 fract(const Vector3 &v) +{ + return { + fract(v[0]), + fract(v[1]), + fract(v[2]) + }; +} + +template +Vector3 trunc(const Vector3 &v) +{ + return { + trunc(v[0]), + trunc(v[1]), + trunc(v[2]) + }; +} + +template +Real distance_relative(const Vector3 &l, const Vector3 &r) +{ + return distance_squared(l, r); +} + + +} // namespace +} // namespace +} // namespace diff --git a/tjp/core/math/Vector4.h b/tjp/core/math/Vector4.h new file mode 100755 index 0000000..ce5d3a8 --- /dev/null +++ b/tjp/core/math/Vector4.h @@ -0,0 +1,28 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Real.h" + +namespace tjp { +namespace core { +namespace math { + +template +struct Vector4; + +typedef Vector4 Vector4d; +typedef Vector4 Vector4f; +typedef Vector4 Vector4r; +typedef Vector4 Vector4i; + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Vector4.hpp b/tjp/core/math/Vector4.hpp new file mode 100755 index 0000000..e8b7d03 --- /dev/null +++ b/tjp/core/math/Vector4.hpp @@ -0,0 +1,137 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Vector4.h" +#include "Vector3.h" +#include "Zero.h" +#include + +namespace tjp { +namespace core { +namespace math { + +template +struct Vector4_ { + using V = Real[4]; + V v; + + Real &operator[](size_t i) { return v[i]; } + Real const &operator[](size_t i) const { return v[i]; }; +} ; + +template +struct Vector4 +{ + using Real = T; + using V = Vector4_; + V v; + + constexpr Vector4(int zero) : + v { static_cast(zero), static_cast(zero), static_cast(zero) } + {} + + constexpr Vector4() = default; + constexpr Vector4(const Vector4 &) = default; + constexpr Vector4(const V &rhs) : v (rhs) {} + constexpr Vector4(const std::initializer_list &v_) + { + auto i = 0; + for (auto &n: v_) + v[i++] = n; + } + + constexpr Vector4& operator=(const Vector4 &) = default; + constexpr Vector4& operator=(const V &v_) + { + v = v_; + return *this; + } + + constexpr Vector4(const Vector3_ &v3, Real w) + : v {v3[0], v3[1], v3[2], w} + {} + + constexpr Vector4(Real x, Real y, Real z, Real w) + : v {x, y, z, w} + {} + + operator V() + { + return { v[0], v[1], v[2], v[3] }; + } + + template + Vector4 asType() const + { + return Vector4 { (U)v[0], (U)v[1], (U)v[2], (U)v[3] }; + } + + Tuple, T> as3p1() const + { + return { + Vector3 { v[0], v[1], v[2] }, + v[3] + }; + } + + T &operator[](size_t i) + { + return v[i]; + } + + const T &operator[](size_t i) const + { + return v[i]; + } + + Vector3 xyz() const + { + return {v[0], v[1], v[2] }; + } + + Real w() const + { + return v[3]; + } + +// operator bool() const +// { +// return +// v[0] != 0 || +// v[1] != 0 || +// v[2] != 0 || +// v[3] != 0; +// } +// +// bool operator!() const +// { +// return +// v[0] == 0 && +// v[1] == 0 && +// v[2] == 0 && +// v[3] == 0; +// } + +public: + static const Vector4 Zero; +} ; + +template +const Vector4 Vector4::Zero = { + zero(), + zero(), + zero(), + zero() +}; + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/Vector4.inl b/tjp/core/math/Vector4.inl new file mode 100755 index 0000000..176b3aa --- /dev/null +++ b/tjp/core/math/Vector4.inl @@ -0,0 +1,154 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Vector4.hpp" +#include "Vector3.hpp" +#include "Real.inl" + +namespace tjp::core::math { + +template +bool operator ==(const Vector4_ &l, const Vector4_ &r) +{ + return + l[0] == r[0] && + l[1] == r[1] && + l[2] == r[2] && + l[3] == r[3]; +} + +template +bool operator !=(const Vector4_ &l, const Vector4_ &r) +{ + return + l[0] != r[0] || + l[1] != r[1] || + l[2] != r[2] || + l[3] != r[3]; +} + +template +bool operator !=(const Vector4 &l, const Vector4 &r) { return l.v != r.v; } + +template +bool operator ==(const Vector4 &l, const Vector4 &r) { return l.v == r.v; } + + +template +void zero(Vector4 &v) +{ + v = Vector4(0,0,0,0); +} + +//template +//Vector4 Vector4_(const Vector3 &l, const float a) +//{ +// return { l[0], l[1], l[2], a }; +//} + +template +Vector4 operator +(const Vector4 &l, const Vector4 &r) +{ + return { l[0] + r[0], l[1] + r[1], l[2] + r[2], l[3] + r[3] }; +} + +// inline +template +Vector4 operator -(const Vector4 &l, const Vector4 &r) +{ + return { l[0] - r[0], l[1] - r[1], l[2] - r[2], l[3] + r[3] }; +} + +template +void operator -=(Vector4 &l, const Vector4 &r) +{ + l[0] -= r[0]; + l[1] -= r[1]; + l[2] -= r[2]; + l[3] -= r[3]; +} + +// inline +template +Vector4 operator *(const Vector4 &l, U r) +{ + return Vector4 { + l[0] * r, + l[1] * r, + l[2] * r, + l[3] * r + }; +} + +template +Real dot(const Vector4 &l, const Vector4 &r) +{ + return + l[0] * r[0] + + l[1] * r[1] + + l[2] * r[2] + + l[3] * r[3] + ; +} + +template +Vector4 operator *(U r, const Vector4 &l) +{ + return l * r; +} + +template +Vector4 operator /(U l, const Vector4 &r) +{ + return { + l/r[0], + l/r[1], + l/r[2], + l/r[3] + }; +} + +template +Vector4 operator /(const Vector4 &l, U r) +{ + return { + l[0]/r, + l[1]/r, + l[2]/r, + l[3]/r + }; +} + + +template +Vector4 fract(const Vector4 &v) +{ + return { + fract(v[0]), + fract(v[1]), + fract(v[2]), + fract(v[3]) + }; +} + +template +Vector4 trunc(const Vector4 &v) +{ + return { + trunc(v[0]), + trunc(v[1]), + trunc(v[2]), + trunc(v[3]) + }; +} + + + +} // namespace diff --git a/tjp/core/math/Zero.h b/tjp/core/math/Zero.h new file mode 100755 index 0000000..96c1fae --- /dev/null +++ b/tjp/core/math/Zero.h @@ -0,0 +1,33 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +namespace tjp::core::math { + +template +void zero(T &t) +{ + t = T{0}; +} + +template +T zero() +{ + T t; + zero(t); + return t; +} + +template +bool is_zero(const T &t) +{ + return t == zero(); +} + +} // namespace diff --git a/tjp/core/math/_delete/BigDecimal+IO+Test.cpp b/tjp/core/math/_delete/BigDecimal+IO+Test.cpp new file mode 100644 index 0000000..8fa9d40 --- /dev/null +++ b/tjp/core/math/_delete/BigDecimal+IO+Test.cpp @@ -0,0 +1,50 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#include "BigDecimal+IO.h" + +#include +#include +#include + +#include + +namespace tjp { +namespace core { +namespace math { +namespace test { + +SCENARIO("big decimal io") +{ + GIVEN("a number") + { + auto a = BigDecimal::fromSignificandExponent(10923905823095,-5); + + WHEN("bin") + { + auto s = io::bin::serialize(a); + auto b = io::bin::deserialize(s); + + REQUIRE(a == b); + } + + WHEN("json") + { + auto s = io::json::serialize(a); + auto b = io::json::deserialize(s); + + REQUIRE(a == b); + } + } +} + +} // namespace +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/_delete/BigDecimal+IO.cpp b/tjp/core/math/_delete/BigDecimal+IO.cpp new file mode 100755 index 0000000..dc36eda --- /dev/null +++ b/tjp/core/math/_delete/BigDecimal+IO.cpp @@ -0,0 +1,60 @@ +// +// Math.cpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#include "BigDecimal+IO.h" + +#include + +namespace tjp { +namespace core { +namespace math { + +std::ostream &operator <<(std::ostream &o, const BigDecimal &m) +{ + std::string num_ = core::to_string(m.significand); + std::string_view num = num_; + + auto leading = (s32)num.length() + m.exp; + if (leading <= 0) + { + o << "0."; + while (leading++ < 0) + o << "0"; + + o << num; + + return o; + } + else + { + s32 lastNonZero = num.size(); + for (; lastNonZero>0; --lastNonZero) + if (num[lastNonZero-1] != '0') + break; + + auto left = std::min(lastNonZero, leading); + auto right = lastNonZero - left; + auto zeros = leading - lastNonZero; + + o << num.substr(0, left); + + if (right > 0) + o << "."; + + o << num.substr(left, right); + + while (zeros-- > 0) + o << "0"; + } + + return o; +} + +} // namespace +} // namespace +} // namespace diff --git a/tjp/core/math/_delete/BigDecimal+IO.h b/tjp/core/math/_delete/BigDecimal+IO.h new file mode 100644 index 0000000..ce8c5fe --- /dev/null +++ b/tjp/core/math/_delete/BigDecimal+IO.h @@ -0,0 +1,41 @@ +// +// MathIO.h +// common +// +// Created by Timothy Prepscius on 8/4/18. +// Copyright © 2018 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "BigDecimal.hpp" +#include "BigInt+IO.h" + +#include + +namespace tjp { +namespace core { +namespace math { + +std::ostream &operator <<(std::ostream &o, const BigDecimal &m); + +template +void io_(IO &io, BigDecimal &v) +{ + io.object("significand", v.significand, "exp", v.exp); + +#ifdef DEBUG_BIGDECIMAL + generateDebug(v); +#endif +} + +template +void io_bin(IO &io, BigDecimal &v) { return io_(io, v); } + +template +void io_json(IO &io, BigDecimal &v) { return io_(io, v); } + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/_delete/BigDecimal+Test.cpp b/tjp/core/math/_delete/BigDecimal+Test.cpp new file mode 100755 index 0000000..019dc05 --- /dev/null +++ b/tjp/core/math/_delete/BigDecimal+Test.cpp @@ -0,0 +1,194 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#include "BigDecimal.h" +#include "BigDecimal+IO.h" + +#include "Algorithm.hpp" + +#include +#include +#include + +namespace tjp { +namespace core { +namespace math { +namespace test { + +SCENARIO("big decimal") +{ + auto a3_5 = BigDecimal::fromIntegerDecimalExponent(3,5); + auto a3_5124124 = BigDecimal::fromIntegerDecimalExponent(3,5124124); + auto a0_005124124 = BigDecimal::fromIntegerDecimalExponent(5,124124,-3); + auto a0_006124124 = BigDecimal::fromIntegerDecimalExponent(6,124124,-3); + auto a30000 = BigDecimal::fromIntegerDecimalExponent(3,0,4); + auto a30001 = BigDecimal::fromIntegerDecimalExponent(30001,0); + auto a30000_2 = BigDecimal::fromIntegerDecimalExponent(30000,2); + + GIVEN("a number") + { + REQUIRE(core::to_string(a3_5) == "3.5"); + REQUIRE(core::to_string(a3_5124124) == "3.5124124"); + REQUIRE(core::to_string(a0_005124124) == "0.005124124"); + REQUIRE(core::to_string(a0_006124124) == "0.006124124"); + REQUIRE(core::to_string(a30000) == "30000"); + REQUIRE(core::to_string(a30001) == "30001"); + REQUIRE(core::to_string(a30000_2) == "30000.2"); + + REQUIRE(core::to_string(a30000/1) == "30000"); + } + + GIVEN("a number") + { + REQUIRE(a3_5.getInteger() == 3); + REQUIRE(a3_5124124.getInteger() == 3); + REQUIRE(a0_005124124.getInteger() == 0); + REQUIRE(a30000.getInteger() == 30000); + REQUIRE(a30000_2.getInteger() == 30000); + + auto a_5 = BigDecimal::fromIntegerDecimalExponent(0,5); + auto a_5124124 = BigDecimal::fromIntegerDecimalExponent(0,5124124); + auto a_005124124 = BigDecimal::fromIntegerDecimalExponent(0,5124124, -2); + auto a_0 = BigDecimal(); + auto a_2 = BigDecimal::fromIntegerDecimalExponent(0,2); + + REQUIRE(a3_5.getDecimal() == a_5); + REQUIRE(a3_5124124.getDecimal() == a_5124124); + REQUIRE(a0_005124124.getDecimal() == a_005124124); + REQUIRE(a30000.getDecimal() == a_0); + REQUIRE(a30000_2.getDecimal() == a_2); + } + GIVEN("reals") + { + auto b30001 = BigDecimal(30001); + auto b3_5 = BigDecimal(3.5); + auto b3_5124124 = BigDecimal(3.5124124); + auto b0_005124124 = BigDecimal(0.005124124); + auto b0_006124124 = BigDecimal(0.006124124); + + auto b30001_s = core::to_string(b30001); + + auto sigma = BigDecimal(0.0001); + REQUIRE(distance(a3_5, b3_5) < sigma); + REQUIRE(distance(a3_5124124, b3_5124124) < sigma); + REQUIRE(distance(a0_005124124, b0_005124124) < sigma); + REQUIRE(distance(a0_006124124, b0_006124124) < sigma); + + REQUIRE(distance(a30001, b30001) < sigma); + } + + GIVEN("numbers") + { + auto b3_5 = BigDecimal::fromIntegerDecimalExponent(3,5); + + REQUIRE (a3_5 < a3_5124124); + REQUIRE (a3_5 <= a3_5124124); + REQUIRE (a3_5124124 > a3_5); + + REQUIRE (a0_005124124 < a0_006124124); + REQUIRE (a0_005124124 <= a0_006124124); + REQUIRE (a0_006124124 > a0_005124124); + + REQUIRE (a3_5 <= b3_5); + } + + GIVEN("a number") + { + auto a = BigDecimal::fromIntegerDecimalExponent(3,5); + auto b = BigDecimal::fromIntegerDecimalExponent(7,3); + + auto a_ = core::to_string(a); + auto b_ = core::to_string(b); + + WHEN("add") + { + auto c = a + b; + auto c_ = core::to_string(c); + + REQUIRE(c == BigDecimal::fromIntegerDecimalExponent(10,8)); + } + + WHEN("multiply") + { + auto c = a / b; + auto c_ = core::to_string(c); + + auto c_s = std::string("0.4794"); + REQUIRE(core::starts_with(c_, c_s)); + + } + + WHEN("divide") + { + auto c = a * b; + auto c_ = core::to_string(c); + + REQUIRE(c == BigDecimal::fromIntegerDecimalExponent(25, 55)); + } + + WHEN("sqrt") + { + auto a = BigDecimal::fromIntegerDecimalExponent(20,25); + auto b = sqrt(a); + + auto a_ = core::to_string(a); + auto b_ = core::to_string(b); + + REQUIRE(b == BigDecimal::fromIntegerDecimalExponent(4,5)); + + auto c = BigDecimal::fromIntegerDecimalExponent(300000,0,-5); + + auto s = std::sqrt(3.0); + auto d_s = std::string("1.73205"); + + auto d = sqrt(c); + auto d_ = core::to_string(d); + + REQUIRE(core::starts_with(d_, d_s)); + } + } + + GIVEN("a number to reduce") + { + auto a = BigDecimal::fromIntegerDecimalExponent(100,0,0); + auto b = BigDecimal::fromIntegerDecimalExponent(1,0,2); + + REQUIRE(a == b); + reduce(a); + + auto a_ = core::to_string(a); + auto b_ = core::to_string(b); + + REQUIRE(a == b); + REQUIRE(a.significand == 1); + REQUIRE(a.exp == b.exp); + REQUIRE(a.significand == b.significand); + } + + GIVEN("a number to reduce < 1") + { + auto a = BigDecimal::fromIntegerDecimalExponent(100,0,-4); + auto b = BigDecimal::fromIntegerDecimalExponent(1,0,-2); + REQUIRE(a == b); + reduce(a); + + auto a_ = core::to_string(a); + auto b_ = core::to_string(b); + + REQUIRE(a == b); + REQUIRE(a.significand == 1); + REQUIRE(a.exp == b.exp); + REQUIRE(a.significand == b.significand); + } +} + +} // namespace +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/_delete/BigDecimal.cpp b/tjp/core/math/_delete/BigDecimal.cpp new file mode 100755 index 0000000..932ff1b --- /dev/null +++ b/tjp/core/math/_delete/BigDecimal.cpp @@ -0,0 +1,353 @@ +// +// Math.cpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#include "BigDecimal.hpp" +#include "BigDecimal+IO.h" +#include +#include +#include + +#include "Real.inl" +#include "BigInt+Imp.hpp" + +namespace tjp { +namespace core { +namespace math { + +BigDecimal BigDecimal::Zero(0); + +// ------- + +static BigInt::Imp::V ten(10); +double sqrt_10 = sqrt(10.0); + +#ifdef _DEBUG +#define DEBUG_BIGDECIMAL +#endif + +#ifdef DEBUG_BIGDECIMAL +void generateDebug(BigDecimal &d) +{ + d.debug = core::to_string(d); +} +#endif + +void reduce(BigDecimal &v) +{ + while (!is_zero(v.significand) && is_zero(v.significand % 10)) + { + v.significand /= 10; + v.exp++; + } + + generateDebug(v); +} + +size_t numDigits(const BigInt &v_) +{ + if (is_zero(v_)) + return 0; + + auto v = v_; + size_t length = 0; + while (!is_zero(v)) + { + v /= 10; + length++; + } + + return length; +} + +// ------- + +BigDecimal::BigDecimal() : + exp(0) +{ + generateDebug(*this); +} + +BigDecimal::BigDecimal(const math::Real &real) : + BigDecimal(real, 16) +{} + +BigDecimal::BigDecimal(const math::Real &real, s32 precision) +{ + long double d = real; + d *= std::pow(10.0, precision); + + auto d_ = std::to_string(d); + + std::string_view v = d_; + + debug_assert(v.find('E') == -1); + v = v.substr(0, v.find('.')); + + long i = v.size()-1; + for (; i>=0; --i) + { + if (v[i] != '0') + break; + } + + if (i < 0 || (v[i] == '-')) + { + exp = 0; + + generateDebug(*this); + return; + } + + precision -= (v.size()-1 - i); + significand = BigInt(v.substr(0, i+1)); + exp = -precision; + + generateDebug(*this); +} + +BigDecimal::BigDecimal(BigInt &&significand_, s32 exp_) : + significand(significand_), + exp(exp_) +{ + generateDebug(*this); +} + +BigDecimal::BigDecimal(const BigInt &integer, const BigInt &decimal, s32 exp_) +{ + auto precision = (s32)numDigits(decimal); + auto m = boost::multiprecision::pow(ten, precision); + significand = BigInt::Imp { m * integer.imp->v + decimal.imp->v }; + exp = exp_ - precision; + + generateDebug(*this); +} + +// ------------------ + +BigDecimal BigDecimal::fromInteger(BigInt &&significand_) +{ + return fromSignificandExponent(std::move(significand_), 0); +} + + +BigDecimal BigDecimal::fromReal(math::Real real, int precision) +{ + return BigDecimal(real, precision); +} + +BigDecimal BigDecimal::fromIntegerDecimalExponent(const BigInt &integer, const BigInt &decimal, s32 exp) +{ + return BigDecimal(integer, decimal, exp); +} + +BigDecimal BigDecimal::fromSignificandExponent(BigInt &&significand, s32 exp) +{ + return BigDecimal(std::move(significand), exp); +} + +BigInt BigDecimal::getInteger() const +{ + auto m = boost::multiprecision::pow(ten, std::abs(exp)); + if (exp > 0) + return BigInt::Imp { m * significand.imp->v }; + else + return BigInt::Imp { significand.imp->v / m }; +} + +BigDecimal BigDecimal::getDecimal() const +{ + if (exp >= 0) + return BigDecimal(); + + auto m = boost::multiprecision::pow(ten, -exp); + + return BigDecimal(BigInt::Imp { significand.imp->v % m }, exp); +} + + +// ------------------ + + +template<> +BigDecimal sqrt(const BigDecimal &v) +{ + // a = sqrt(10^d * v) + // a = sqrt(10^d) * sqrt(v) + // a = sqrt(10^(d/2)) * sqrt(v) + + auto addedPrecision = 6; + auto addedOffset = v.exp % 2 ? 1 : 0; + auto offset = addedPrecision + addedOffset; + + auto m = boost::multiprecision::pow(ten, offset); + auto vp = BigInt::Imp::V(v.significand.imp->v * m); + auto vpr = boost::multiprecision::sqrt(vp); + + auto result = BigDecimal::fromSignificandExponent( + BigInt::Imp { std::move(vpr) }, + (v.exp - offset) / 2 + ); + +/* + auto v_ = core::to_string(v); + auto vp_ = core::to_string(vp); + auto vpr_ = core::to_string(vpr); + auto result_ = core::to_string(result); +*/ + + return result; +} + +template<> +BigDecimal abs(const BigDecimal &v) +{ + return BigDecimal::fromSignificandExponent( abs(v.significand), v.exp ); +} + +BigDecimal operator*(const BigDecimal &lhs, const BigDecimal &rhs) +{ + // 1.5 = 15, 1 + // 13 = 13, 0 + // 19.5 = 195, 1 + + return BigDecimal::fromSignificandExponent(lhs.significand * rhs.significand, lhs.exp + rhs.exp); +} + +BigDecimal operator/(const BigDecimal &lhs, const BigDecimal &rhs) +{ + static auto precision = 6; + static auto m = boost::multiprecision::pow(ten, precision); + + return BigDecimal::fromSignificandExponent( + BigInt::Imp{ m * lhs.significand.imp->v / rhs.significand.imp->v }, + lhs.exp - rhs.exp - precision + ); +} + +BigDecimal operator/(const BigDecimal &lhs, size_t rhs) +{ + return lhs / BigDecimal(rhs); +} + + +BigDecimal operator+(const BigDecimal &lhs, const BigDecimal &rhs) +{ + if (lhs.exp > rhs.exp) + return rhs + lhs; + + // 1.5 = 15, 1 + // 10 = 10, 0 + + auto m = boost::multiprecision::pow(ten, rhs.exp - lhs.exp); + auto v = m * rhs.significand.imp->v; + auto s = v + lhs.significand.imp->v; + + auto result = BigDecimal::fromSignificandExponent(BigInt::Imp { s }, lhs.exp); + + auto lhs_ = core::to_string(lhs); + auto rhs_ = core::to_string(rhs); + + auto lhs_s = core::to_string(lhs.significand); + auto rhs_s = core::to_string(rhs.significand); + + auto m_ = core::to_string(BigInt(BigInt::Imp { m })); + auto v_ = core::to_string(BigInt(BigInt::Imp { v })); + auto s_ = core::to_string(BigInt(BigInt::Imp { s })); + auto result_ = core::to_string(result); + + return result; +} + +BigDecimal operator-(const BigDecimal &lhs, const BigDecimal &rhs) +{ + return lhs + (-rhs); +} + +BigDecimal operator-(const BigDecimal &v) +{ + return BigDecimal::fromSignificandExponent(BigInt::Imp { -v.significand.imp->v }, v.exp); +} + +void normalize(BigDecimal &lhs, BigDecimal &rhs) +{ + if (lhs.exp == rhs.exp) + return; + + auto *big = (lhs.exp < rhs.exp) ? &rhs : &lhs; + auto *small = (lhs.exp < rhs.exp) ? &lhs : &rhs; + + auto d = big->exp - small->exp; + auto m = boost::multiprecision::pow(ten, d); + + big->significand.imp->v *= m; + big->exp -= d; + + generateDebug(lhs); + generateDebug(rhs); +} + + +bool operator==(const BigDecimal &lhs, const BigDecimal &rhs) +{ + // 10 = 1, 1 + // 10 = 10, 0 + + if (lhs.exp == rhs.exp) + return lhs.significand == rhs.significand; + + auto lhs_ = lhs; + auto rhs_ = rhs; + normalize(lhs_, rhs_); + + return (lhs_.significand == rhs_.significand); +} + +bool operator<(const BigDecimal &lhs, const BigDecimal &rhs) +{ + if (lhs.exp == rhs.exp) + return lhs.significand < rhs.significand; + + auto lhs_ = lhs; + auto rhs_ = rhs; + normalize(lhs_, rhs_); + + return lhs_.significand < rhs_.significand; +} + +bool operator<=(const BigDecimal &lhs, const BigDecimal &rhs) +{ + if (lhs.exp == rhs.exp) + return lhs.significand <= rhs.significand; + + auto lhs_ = lhs; + auto rhs_ = rhs; + normalize(lhs_, rhs_); + + return lhs_.significand <= rhs_.significand; +} + +bool operator!=(const BigDecimal &lhs, const BigDecimal &rhs) +{ + return !(lhs == rhs); +} + +bool operator>(const BigDecimal &lhs, const BigDecimal &rhs) +{ + return rhs < lhs; +} + +bool operator>=(const BigDecimal &lhs, const BigDecimal &rhs) +{ + return rhs <= lhs; +} + + + +} // namespace +} // namespace +} // namespace diff --git a/tjp/core/math/_delete/BigDecimal.h b/tjp/core/math/_delete/BigDecimal.h new file mode 100755 index 0000000..6d560c3 --- /dev/null +++ b/tjp/core/math/_delete/BigDecimal.h @@ -0,0 +1,20 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +namespace tjp { +namespace core { +namespace math { + +struct BigDecimal; + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/_delete/BigDecimal.hpp b/tjp/core/math/_delete/BigDecimal.hpp new file mode 100755 index 0000000..30b8b1b --- /dev/null +++ b/tjp/core/math/_delete/BigDecimal.hpp @@ -0,0 +1,82 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "BigInt.h" +#include "Real.h" + +#define DEBUG_BIGDECIMAL + +namespace tjp { +namespace core { +namespace math { + +struct BigDecimal { + BigInt significand; + s32 exp = 0; + +#ifdef DEBUG_BIGDECIMAL + std::string debug; +#endif + + BigDecimal(); + explicit BigDecimal(const math::Real &real); + explicit BigDecimal(const math::Real &real, s32 precision); + + static BigDecimal fromInteger(BigInt &&integer); + static BigDecimal fromIntegerDecimalExponent(const BigInt &integer, const BigInt &decimal, s32 exp=0); + static BigDecimal fromReal(math::Real real, s32 precision=16); + static BigDecimal fromSignificandExponent(BigInt &&significand, s32 exp); + + BigInt getInteger() const; + BigDecimal getDecimal() const; + + static BigDecimal Zero; + +protected: + BigDecimal(BigInt &&integer, s32 exp); + BigDecimal(const BigInt &integer, const BigInt &decimal, s32 exp); +}; + +#ifdef DEBUG_BIGDECIMAL +void generateDebug(BigDecimal &v); +#else +inline +void generateDebug(BigDecimal &) {} +#endif + +template<> +BigDecimal sqrt(const BigDecimal &); + +template<> +BigDecimal abs(const BigDecimal &); + +BigDecimal operator-(const BigDecimal &lhs); +BigDecimal operator-(const BigDecimal &lhs, const BigDecimal &rhs); +BigDecimal operator+(const BigDecimal &lhs, const BigDecimal &rhs); +BigDecimal operator*(const BigDecimal &lhs, const BigDecimal &rhs); +BigDecimal operator/(const BigDecimal &lhs, const BigDecimal &rhs); + +BigDecimal operator/(const BigDecimal &lhs, size_t rhs); + + +bool operator==(const BigDecimal &lhs, const BigDecimal &rhs); +bool operator!=(const BigDecimal &lhs, const BigDecimal &rhs); +bool operator<(const BigDecimal &lhs, const BigDecimal &rhs); +bool operator<=(const BigDecimal &lhs, const BigDecimal &rhs); +bool operator>(const BigDecimal &lhs, const BigDecimal &rhs); +bool operator>=(const BigDecimal &lhs, const BigDecimal &rhs); + +void reduce(BigDecimal &); +void normalize(BigDecimal &lhs, BigDecimal &rhs); + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/_delete/BigInt+IO+Test.cpp b/tjp/core/math/_delete/BigInt+IO+Test.cpp new file mode 100644 index 0000000..5a7b757 --- /dev/null +++ b/tjp/core/math/_delete/BigInt+IO+Test.cpp @@ -0,0 +1,50 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#include "BigInt+IO.h" + +#include +#include +#include + +#include + +namespace tjp { +namespace core { +namespace math { +namespace test { + +SCENARIO("big int io") +{ + GIVEN("a number") + { + BigInt a = 10923905823095; + + WHEN("bin") + { + auto s = io::bin::serialize(a); + auto b = io::bin::deserialize(s); + + REQUIRE(a == b); + } + + WHEN("json") + { + auto s = io::json::serialize(a); + auto b = io::json::deserialize(s); + + REQUIRE(a == b); + } + } +} + +} // namespace +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/_delete/BigInt+IO.cpp b/tjp/core/math/_delete/BigInt+IO.cpp new file mode 100644 index 0000000..373e05d --- /dev/null +++ b/tjp/core/math/_delete/BigInt+IO.cpp @@ -0,0 +1,41 @@ +// +// MathIO.h +// common +// +// Created by Timothy Prepscius on 8/4/18. +// Copyright © 2018 Timothy Prepscius. All rights reserved. +// + +#include "BigInt+IO.h" +#include "BigInt+Imp.hpp" +#include + +namespace tjp { +namespace core { +namespace math { + +void write(const BigInt &v, Vector &bytes) +{ + auto *mp = &v.imp->v.backend().data(); + auto binSize = mp_ubin_size(mp); + + bytes.resize(binSize); + + size_t written; + auto error = mp_to_ubin(mp, (unsigned char *)bytes.data(), bytes.size(), &written); + debug_assert(written == binSize); + debug_assert(error == 0); +} + +void read(BigInt &v, const Vector &bytes) +{ + auto *mp = &v.imp->v.backend().data(); + + auto error = mp_from_ubin(mp, (unsigned char *)bytes.data(), bytes.size()); + debug_assert(error == 0); +} + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/_delete/BigInt+IO.h b/tjp/core/math/_delete/BigInt+IO.h new file mode 100644 index 0000000..6a60fcb --- /dev/null +++ b/tjp/core/math/_delete/BigInt+IO.h @@ -0,0 +1,54 @@ +// +// MathIO.h +// common +// +// Created by Timothy Prepscius on 8/4/18. +// Copyright © 2018 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "BigInt.h" + +#include + +namespace tjp { +namespace core { +namespace math { + + +void write(const BigInt &v, Vector &bytes); +void read(BigInt &, const Vector &bytes); + +template +void io_w(IO &io, const tjp::core::math::BigInt &v) +{ + std::vector bytes; + write(v, bytes); + io.any(bytes); +} + +template +void io_r(IO &io, tjp::core::math::BigInt &v) +{ + std::vector bytes; + io.any(bytes); + read(v, bytes); +} + +template +void io_bin_w(IO &io, const tjp::core::math::BigInt &v) { return io_w(io, v); } + +template +void io_json_w(IO &io, const tjp::core::math::BigInt &v) { return io_w(io, v); } + +template +void io_bin_r(IO &io, tjp::core::math::BigInt &v) { return io_r(io, v); } + +template +void io_json_r(IO &io, tjp::core::math::BigInt &v) { return io_r(io, v); } + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/_delete/BigInt+Imp.hpp b/tjp/core/math/_delete/BigInt+Imp.hpp new file mode 100755 index 0000000..5a035fc --- /dev/null +++ b/tjp/core/math/_delete/BigInt+Imp.hpp @@ -0,0 +1,29 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include +#include +#include + +#include "Real.h" + +namespace tjp { +namespace core { +namespace math { + +struct BigInt::Imp { + typedef boost::multiprecision::tom_int V; + V v; +} ; + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/_delete/BigInt+Test.cpp b/tjp/core/math/_delete/BigInt+Test.cpp new file mode 100755 index 0000000..969a0b1 --- /dev/null +++ b/tjp/core/math/_delete/BigInt+Test.cpp @@ -0,0 +1,63 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#include "BigInt.h" + +#include + +namespace tjp { +namespace core { +namespace math { +namespace test { + +SCENARIO("big int") +{ + GIVEN("a number") + { + BigInt a = 1; + + WHEN("add") + { + a += 2; + + REQUIRE(a == 3); + } + + WHEN("sqrt") + { + a = 17; + auto b = sqrt(a); + + REQUIRE(b == 4); + } + + WHEN("and") + { + a = 32767; + auto b = a & 0xFF; + + REQUIRE(b == 0xFF); + } + + WHEN("shift") + { + a = 0xDEDEFEFE; + auto b = a >> 16; + + REQUIRE(b == 0xDEDE); + } + + + } +} + +} // namespace +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/_delete/BigInt.cpp b/tjp/core/math/_delete/BigInt.cpp new file mode 100755 index 0000000..c8ee375 --- /dev/null +++ b/tjp/core/math/_delete/BigInt.cpp @@ -0,0 +1,235 @@ +// +// Math.cpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#include "BigInt.hpp" +#include "BigInt+Imp.hpp" + +#include + +namespace tjp { +namespace core { +namespace math { + +BigInt BigInt::Zero(0); + +BigInt::Imp::V &m(BigInt &v) +{ + return v.imp->v; +} + +const BigInt::Imp::V &m(const BigInt &v) +{ + return v.imp->v; +} + +BigInt::Imp::V &c(BigInt &v) +{ + if (v.imp == nullptr) + v.imp = core::strong(); + + return m(v); +} + + +BigInt::Imp::V &c(const BigInt &v) +{ + return c(remove_const_of_var(v)); +} + + +BigInt::BigInt() +{ + c(*this); +} + +BigInt::BigInt(s64 v) +{ + c(*this) = v; +} + +BigInt::BigInt(Imp &&imp_) : + imp(core::strong(std::move(imp_))) +{ +} + +BigInt::BigInt(const StringView &s) +{ + c(*this) = Imp::V(s); +} + +BigInt::BigInt(const BigInt &v) +{ + c(*this) = m(v); +} + +s64 BigInt::toInteger() const +{ + return c(*this).convert_to(); +} + + + +template<> +BigInt sqrt(const BigInt &b) +{ + BigInt result; + c(result) = boost::multiprecision::sqrt(m(b)); + + return result; +} + +template<> +BigInt abs(const BigInt &b) +{ + BigInt result; + c(result) = boost::multiprecision::abs(m(b)); + return result; +} + +template<> +BigInt pow2(const BigInt &b) +{ + BigInt result; + c(result) = m(b) * m(b); + return result; +} + +bool is_zero(const BigInt &lhs) +{ + return m(lhs).is_zero(); +} + +BigInt operator %(const BigInt &lhs, int rhs) +{ + BigInt r; + c(r) = m(lhs) % rhs; + return r; +} + +BigInt operator %(const BigInt &lhs, const BigInt &rhs) +{ + BigInt r; + c(r) = m(lhs) % m(rhs); + return r; +} + +BigInt operator /(const BigInt &lhs, int rhs) +{ + BigInt r; + c(r) = m(lhs) / rhs; + return r; +} + +BigInt operator /(const BigInt &lhs, size_t rhs) +{ + BigInt r; + c(r) = m(lhs) / rhs; + return r; +} + +BigInt &operator /=(BigInt &lhs, int rhs) +{ + m(lhs) = m(lhs) / rhs; + return lhs; +} + +BigInt operator *(int lhs, const BigInt &rhs) +{ + BigInt r; + c(r) = lhs * m(rhs); + return r; +} + +BigInt operator *(const BigInt &rhs, int lhs) +{ + return lhs * rhs; +} + +BigInt operator +(const BigInt &lhs, const BigInt &rhs) +{ + BigInt r; + c(r) = m(lhs) + m(rhs); + return r; +} + +BigInt operator -(const BigInt &lhs, const BigInt &rhs) +{ + BigInt r; + c(r) = m(lhs) - m(rhs); + return r; +} + +BigInt operator *(const BigInt &lhs, const BigInt &rhs) +{ + BigInt r; + c(r) = m(lhs) * m(rhs); + return r; +} + + +BigInt operator /(const BigInt &lhs, const BigInt &rhs) +{ + BigInt r; + c(r) = m(lhs) / m(rhs); + return r; +} + +math::Real toReal(const BigInt &lhs) +{ + return m(lhs).convert_to(); +} + +bool operator ==(const BigInt &lhs, const BigInt &rhs) +{ + return m(lhs) == m(rhs); +} + +bool operator <(const BigInt &lhs, const BigInt &rhs) +{ + return m(lhs) < m(rhs); +} + +bool operator <=(const BigInt &lhs, const BigInt &rhs) +{ + return m(lhs) <= m(rhs); +} + +bool operator >(const BigInt &lhs, const BigInt &rhs) +{ + return m(lhs) > m(rhs); +} + +bool operator >=(const BigInt &lhs, const BigInt &rhs) +{ + return m(lhs) >= m(rhs); +} + +std::ostream &operator<<(std::ostream &o, const math::BigInt &v) +{ + return o << m(v); +} + +BigInt distance_squared(const BigInt &lhs, const BigInt &rhs) +{ + return pow2(rhs-lhs); +} + +BigInt distance_relative(const BigInt &lhs, const BigInt &rhs) +{ + return distance(lhs,rhs); +} + +BigInt distance(const BigInt &lhs, const BigInt &rhs) +{ + return rhs > lhs ? (rhs-lhs) : (lhs-rhs); +} + +} // namespace + +} // namespace +} // namespace diff --git a/tjp/core/math/_delete/BigInt.h b/tjp/core/math/_delete/BigInt.h new file mode 100755 index 0000000..b34a1ee --- /dev/null +++ b/tjp/core/math/_delete/BigInt.h @@ -0,0 +1,81 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "Real.h" +#include +#include +#include + +#include + +namespace tjp { +namespace core { +namespace math { + +struct BigInt { + struct Imp; + core::StrongPtr imp; + + explicit BigInt(const StringView &v); + explicit BigInt(s64 i); + + BigInt(Imp &&imp); + BigInt(); + BigInt(const BigInt &m); + + static BigInt Zero; + + s64 toInteger() const; +}; + +template<> +BigInt sqrt(const BigInt &); + +template<> +BigInt abs(const BigInt &); + +bool is_zero(const BigInt &lhs); +BigInt operator %(const BigInt &lhs, int rhs); +BigInt operator %(const BigInt &lhs, const BigInt &rhs); +BigInt operator /(const BigInt &lhs, int rhs); +BigInt operator *(const BigInt &lhs, int rhs); +BigInt &operator /=(BigInt &lhs, int rhs); + +BigInt operator /(const BigInt &lhs, size_t rhs); + + +BigInt operator *(int lhs, const BigInt &rhs); +BigInt operator +(const BigInt &lhs, const BigInt &rhs); +BigInt operator -(const BigInt &lhs, const BigInt &rhs); +BigInt operator *(const BigInt &lhs, const BigInt &rhs); +BigInt operator /(const BigInt &lhs, const BigInt &rhs); + +math::Real toReal(const BigInt &lhs); + +bool operator ==(const BigInt &lhs, const BigInt &rhs); +bool operator <(const BigInt &lhs, const BigInt &rhs); +bool operator <=(const BigInt &lhs, const BigInt &rhs); + +bool operator >(const BigInt &lhs, const BigInt &rhs); +bool operator >=(const BigInt &lhs, const BigInt &rhs); + +std::ostream &operator<<(std::ostream &o, const math::BigInt &v); + +BigInt distance_squared(const BigInt &lhs, const BigInt &rhs); +BigInt distance_relative(const BigInt &lhs, const BigInt &rhs); +BigInt distance(const BigInt &lhs, const BigInt &rhs); + +} // namespace + +//std::string to_string(const math::BigInt &t); + +} // namespace +} // namespace + diff --git a/tjp/core/math/_delete/BigInt.hpp b/tjp/core/math/_delete/BigInt.hpp new file mode 100755 index 0000000..feb523d --- /dev/null +++ b/tjp/core/math/_delete/BigInt.hpp @@ -0,0 +1,11 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include "BigInt.h" diff --git a/tjp/core/math/_tests/Algorithm+Segment.cpp b/tjp/core/math/_tests/Algorithm+Segment.cpp new file mode 100755 index 0000000..7edc903 --- /dev/null +++ b/tjp/core/math/_tests/Algorithm+Segment.cpp @@ -0,0 +1,79 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#include + +#include + +namespace tjp { +namespace core { +namespace math { +namespace test { + +SCENARIO("math_segment") +{ + GIVEN("a segment") + { + Segment1 a = { 10, 15 }; + + Segment1 b = {4,9}; + REQUIRE(!intersects(b, a)); + REQUIRE(!intersects(a, b)); + REQUIRE(!contains(b, a)); + REQUIRE(!contains(a, b)); + REQUIRE(intersects(b, a, 1)); + REQUIRE(intersects(a, b, 1)); + + Segment1 c = {9,11}; + REQUIRE(intersects(c, a)); + REQUIRE(intersects(a, c)); + REQUIRE(!contains(c, a)); + REQUIRE(!contains(a, c)); + REQUIRE(intersects(c, a, 1)); + REQUIRE(intersects(a, c, 1)); + + + Segment1 d = {11,11}; + REQUIRE(intersects(d, a)); + REQUIRE(intersects(a, d)); + REQUIRE(!contains(d, a)); + REQUIRE(contains(a, d)); + REQUIRE(intersects(d, a, 1)); + REQUIRE(intersects(a, d, 1)); + + Segment1 e = {11,12}; + REQUIRE(intersects(e, a)); + REQUIRE(intersects(a, e)); + REQUIRE(!contains(e, a)); + REQUIRE(contains(a, e)); + + Segment1 f = {12,16}; + REQUIRE(intersects(f, a)); + REQUIRE(intersects(a, f)); + + Segment1 g = {16,19}; + REQUIRE(!intersects(g, a)); + REQUIRE(!intersects(a, g)); + REQUIRE(intersects(g, a, 1)); + REQUIRE(intersects(a, g, 1)); + + Segment1 h = {4,19}; + REQUIRE(intersects(h, a)); + REQUIRE(intersects(a, h)); + REQUIRE(contains(h, a)); + REQUIRE(!contains(a, h)); + REQUIRE(intersects(h, a, 1)); + REQUIRE(intersects(a, h, 1)); + } +} + +} // namespace +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/math/_tests/Algorithm.cpp b/tjp/core/math/_tests/Algorithm.cpp new file mode 100755 index 0000000..9e24dd7 --- /dev/null +++ b/tjp/core/math/_tests/Algorithm.cpp @@ -0,0 +1,19 @@ +// +// Math.cpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#include +#include +#include + +using namespace tjp::core::math; + +void test_math_algorithm () +{ + Vector2f a, b; + auto c = mul(a, b); +} diff --git a/tjp/core/math/_tests/FloatPack.cpp b/tjp/core/math/_tests/FloatPack.cpp new file mode 100755 index 0000000..07a7187 --- /dev/null +++ b/tjp/core/math/_tests/FloatPack.cpp @@ -0,0 +1,133 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#include +#include + +#include + +#include + +namespace tjp::core::math { +namespace { + +const auto precision = 0.0000000000000000001; + +//template +//bool close(R l, R r) +//{ +// return std::abs(r - l) < precision; +//} + + +bool close(Vector4f l, Vector4f r, r32 p) +{ + for (auto i=0; i<4; ++i) + if (std::abs(l[i] - r[i]) > p) + return false; + + return true; +} + +bool close(Vector3f l, Vector3f r, r32 p) +{ + for (auto i=0; i<3; ++i) + if (std::abs(l[i] - r[i]) > p) + return false; + + return true; +} + +bool close(Vector2f l, Vector2f r, r32 p) +{ + for (auto i=0; i<2; ++i) + if (std::abs(l[i] - r[i]) > p) + return false; + + return true; +} + +SCENARIO("floatpack") +{ +// GIVEN("a number") +// { +// //0.0000000000000000001 +// float a = 0.2412541239199123125; +// +// WHEN("enc-dec-vec4") +// { +// auto v = toVec4f(a); +// auto a_ = toFloat(v); +// +// REQUIRE(close(a, a_)); +// } +// +// WHEN("enc-dec-vec2") +// { +// auto v = toVec2f(a); +// auto a_ = toFloat(v); +// +// REQUIRE(close(a, a_)); +// } +// +// WHEN("enc-dec-vec3") +// { +// auto v = toVec3f(a); +// auto a_ = toFloat(v); +// +// REQUIRE(close(a, a_)); +// } +// } + + GIVEN("a vector") + { + for (auto i=0; i<10000; ++i) + { + auto a = StandardRandom.nextReal(); + auto b = StandardRandom.nextReal(); + auto c = StandardRandom.nextReal(); + auto d = StandardRandom.nextReal(); + + // WHEN("vec4") + { + Vector4f v { a, b, c, d }; + auto a_ = pack4u(v); + auto v_ = unpack4u(a_); + + bool isClose = close(v, v_, 1/float_4_max); + REQUIRE(isClose); + } + + // WHEN("vec3") + { + Vector3f v { a, b, c }; + auto a_ = pack3u(v); + auto v_ = unpack3u(a_); + + bool isClose = close(v, v_, 1/float_3_max); + + REQUIRE(isClose); + } + + // WHEN("vec2") + { + Vector2f v { a, b }; + auto a_ = pack2u(v); + auto v_ = unpack2u(a_); + + bool isClose = close(v, v_, 1/float_2_max); + + REQUIRE(isClose); + } + } + } +} + +} // namespace +} // namespace + diff --git a/tjp/core/math/clamp.hpp b/tjp/core/math/clamp.hpp new file mode 100755 index 0000000..b5ef058 --- /dev/null +++ b/tjp/core/math/clamp.hpp @@ -0,0 +1,24 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +namespace tjp::core::math { + +template +inline V clamp(const V &v, const L &l, const R &r) +{ + if (v < l) + return (V)l; + if (v > r) + return (V)r; + return v; +} + +} // namespace + diff --git a/tjp/core/math/detail/Wm5.cpp b/tjp/core/math/detail/Wm5.cpp new file mode 100644 index 0000000..f9b80ca --- /dev/null +++ b/tjp/core/math/detail/Wm5.cpp @@ -0,0 +1,692 @@ +// +// Wm5.cpp +// algorithm +// +// Created by Timothy Prepscius on 5/3/18. +// Copyright © 2018 Timothy Prepscius. All rights reserved. +// + +#include "Wm5.h" + +#define assertion(...) + +namespace Wm5 { + +template<> const float Math::ZERO_TOLERANCE = 1e-06f; + +template<> const double Math::ZERO_TOLERANCE = 1e-08; + +/************************************************************************/ + +//---------------------------------------------------------------------------- +template +EigenDecomposition::EigenDecomposition (int size) + : + mMatrix(size, size) +{ + assertion(size >= 2, "Invalid size in Eigendecomposition constructor\n"); + + mSize = size; + mDiagonal = new1(mSize); + mSubdiagonal = new1(mSize); + mIsRotation = false; +} +/* +//---------------------------------------------------------------------------- +template +EigenDecomposition::EigenDecomposition (const Matrix2& mat) + : + mMatrix(2, 2, &mat[0][0]) +{ + mSize = 2; + mDiagonal = new1(mSize); + mSubdiagonal = new1(mSize); + mIsRotation = false; +} +//---------------------------------------------------------------------------- +template +EigenDecomposition::EigenDecomposition (const Matrix3& mat) + : + mMatrix(3, 3, &mat[0][0]) +{ + mSize = 3; + mDiagonal = new1(mSize); + mSubdiagonal = new1(mSize); + mIsRotation = false; +} +*/ +//---------------------------------------------------------------------------- +template +EigenDecomposition::EigenDecomposition (const GMatrix& mat) + : + mMatrix(mat) +{ + mSize = mat.GetRows(); + assertion(mSize >= 2 && (mat.GetColumns() == mSize), + "Square matrix required in EigenDecomposition constructor\n"); + + mDiagonal = new1(mSize); + mSubdiagonal = new1(mSize); + mIsRotation = false; +} +//---------------------------------------------------------------------------- +template +EigenDecomposition::~EigenDecomposition () +{ + delete1(mDiagonal); + delete1(mSubdiagonal); +} +//---------------------------------------------------------------------------- +template +Real& EigenDecomposition::operator() (int row, int column) +{ + return mMatrix[row][column]; +} +//---------------------------------------------------------------------------- +/* +template +EigenDecomposition& EigenDecomposition::operator= ( + const Matrix2& mat) +{ + mMatrix.SetMatrix(2, 2, &mat[0][0]); + mSize = 2; + delete1(mDiagonal); + delete1(mSubdiagonal); + mDiagonal = new1(mSize); + mSubdiagonal = new1(mSize); + return *this; +} +//---------------------------------------------------------------------------- +template +EigenDecomposition& EigenDecomposition::operator= ( + const Matrix3& mat) +{ + mMatrix.SetMatrix(3, 3, &mat[0][0]); + mSize = 3; + delete1(mDiagonal); + delete1(mSubdiagonal); + mDiagonal = new1(mSize); + mSubdiagonal = new1(mSize); + return *this; +} +*/ +//---------------------------------------------------------------------------- +template +EigenDecomposition& EigenDecomposition::operator= ( + const GMatrix& mat) +{ + mMatrix = mat; + return *this; +} +//---------------------------------------------------------------------------- +template +void EigenDecomposition::Solve (bool increasingSort) +{ + if (mSize == 2) + { + Tridiagonal2(); + } + else if (mSize == 3) + { + Tridiagonal3(); + } + else + { + TridiagonalN(); + } + + QLAlgorithm(); + + if (increasingSort) + { + IncreasingSort(); + } + else + { + DecreasingSort(); + } + + GuaranteeRotation(); +} +//---------------------------------------------------------------------------- +template +Real EigenDecomposition::GetEigenvalue (int i) const +{ + assertion(0 <= i && i < mSize, "Invalid index in GetEigenvalue\n"); + return mDiagonal[i]; +} +//---------------------------------------------------------------------------- +template +const Real* EigenDecomposition::GetEigenvalues () const +{ + return mDiagonal; +} +//---------------------------------------------------------------------------- +/* +template +Vector2 EigenDecomposition::GetEigenvector2 (int i) const +{ + assertion(mSize == 2, "Mismatched dimension in GetEigenvector2\n"); + + if (mSize == 2) + { + Vector2 eigenvector; + for (int row = 0; row < mSize; ++row) + { + eigenvector[row] = mMatrix[row][i]; + } + return eigenvector; + } + return Vector2::ZERO; +} +//---------------------------------------------------------------------------- +template +Matrix2 EigenDecomposition::GetEigenvectors2 () const +{ + assertion(mSize == 2, "Mismatched dimension in GetEigenvectors2\n"); + + Matrix2 eigenvectors; + for (int row = 0; row < 2; ++row) + { + for (int column = 0; column < 2; ++column) + { + eigenvectors[row][column] = mMatrix[row][column]; + } + } + return eigenvectors; +} +//---------------------------------------------------------------------------- +template +Vector3 EigenDecomposition::GetEigenvector3 (int i) const +{ + assertion(mSize == 3, "Mismatched dimension in GetEigenvector3\n"); + + if (mSize == 3) + { + Vector3 eigenvector; + for (int row = 0; row < mSize; ++row) + { + eigenvector[row] = mMatrix[row][i]; + } + return eigenvector; + } + return Vector3::ZERO; +} +//---------------------------------------------------------------------------- +template +Matrix3 EigenDecomposition::GetEigenvectors3 () const +{ + assertion(mSize == 3, "Mismatched dimension in GetEigenvectors2\n"); + + Matrix3 eigenvectors; + for (int row = 0; row < 3; ++row) + { + for (int column = 0; column < 3; ++column) + { + eigenvectors[row][column] = mMatrix[row][column]; + } + } + return eigenvectors; +} +*/ +//---------------------------------------------------------------------------- +template +GVector EigenDecomposition::GetEigenvector (int i) const +{ + return mMatrix.GetColumn(i); +} +//---------------------------------------------------------------------------- +template +const GMatrix& EigenDecomposition::GetEigenvectors () const +{ + return mMatrix; +} +//---------------------------------------------------------------------------- +template +void EigenDecomposition::Tridiagonal2 () +{ + // The matrix is already tridiagonal. + mDiagonal[0] = mMatrix[0][0]; + mDiagonal[1] = mMatrix[1][1]; + mSubdiagonal[0] = mMatrix[0][1]; + mSubdiagonal[1] = (Real)0; + mMatrix[0][0] = (Real)1; + mMatrix[0][1] = (Real)0; + mMatrix[1][0] = (Real)0; + mMatrix[1][1] = (Real)1; + + mIsRotation = true; +} +//---------------------------------------------------------------------------- +template +void EigenDecomposition::Tridiagonal3 () +{ + Real m00 = mMatrix[0][0]; + Real m01 = mMatrix[0][1]; + Real m02 = mMatrix[0][2]; + Real m11 = mMatrix[1][1]; + Real m12 = mMatrix[1][2]; + Real m22 = mMatrix[2][2]; + + mDiagonal[0] = m00; + mSubdiagonal[2] = (Real)0; + if (Math::FAbs(m02) > Math::ZERO_TOLERANCE) + { + Real length = Math::Sqrt(m01*m01 + m02*m02); + Real invLength = ((Real)1)/length; + m01 *= invLength; + m02 *= invLength; + Real q = ((Real)2)*m01*m12 + m02*(m22 - m11); + mDiagonal[1] = m11 + m02*q; + mDiagonal[2] = m22 - m02*q; + mSubdiagonal[0] = length; + mSubdiagonal[1] = m12 - m01*q; + mMatrix[0][0] = (Real)1; + mMatrix[0][1] = (Real)0; + mMatrix[0][2] = (Real)0; + mMatrix[1][0] = (Real)0; + mMatrix[1][1] = m01; + mMatrix[1][2] = m02; + mMatrix[2][0] = (Real)0; + mMatrix[2][1] = m02; + mMatrix[2][2] = -m01; + mIsRotation = false; + } + else + { + mDiagonal[1] = m11; + mDiagonal[2] = m22; + mSubdiagonal[0] = m01; + mSubdiagonal[1] = m12; + mMatrix[0][0] = (Real)1; + mMatrix[0][1] = (Real)0; + mMatrix[0][2] = (Real)0; + mMatrix[1][0] = (Real)0; + mMatrix[1][1] = (Real)1; + mMatrix[1][2] = (Real)0; + mMatrix[2][0] = (Real)0; + mMatrix[2][1] = (Real)0; + mMatrix[2][2] = (Real)1; + mIsRotation = true; + } +} +//---------------------------------------------------------------------------- +template +void EigenDecomposition::TridiagonalN () +{ + // TODO: This is Numerical Recipes in C code. Rewrite to avoid + // copyright issues. + + int i0, i1, i2, i3; + + for (i0 = mSize - 1, i3 = mSize - 2; i0 >= 1; --i0, --i3) + { + Real value0 = (Real)0; + Real scale = (Real)0; + + if (i3 > 0) + { + for (i2 = 0; i2 <= i3; ++i2) + { + scale += Math::FAbs(mMatrix[i0][i2]); + } + if (scale == (Real)0) + { + mSubdiagonal[i0] = mMatrix[i0][i3]; + } + else + { + Real invScale = ((Real)1)/scale; + for (i2 = 0; i2 <= i3; ++i2) + { + mMatrix[i0][i2] *= invScale; + value0 += mMatrix[i0][i2]*mMatrix[i0][i2]; + } + + Real value1 = mMatrix[i0][i3]; + Real value2 = Math::Sqrt(value0); + if (value1 > (Real)0) + { + value2 = -value2; + } + + mSubdiagonal[i0] = scale*value2; + value0 -= value1*value2; + mMatrix[i0][i3] = value1-value2; + value1 = (Real)0; + Real invValue0 = ((Real)1)/value0; + for (i1 = 0; i1 <= i3; ++i1) + { + mMatrix[i1][i0] = mMatrix[i0][i1]*invValue0; + value2 = (Real)0; + for (i2 = 0; i2 <= i1; ++i2) + { + value2 += mMatrix[i1][i2]*mMatrix[i0][i2]; + } + for (i2 = i1+1; i2 <= i3; ++i2) + { + value2 += mMatrix[i2][i1]*mMatrix[i0][i2]; + } + mSubdiagonal[i1] = value2*invValue0; + value1 += mSubdiagonal[i1]*mMatrix[i0][i1]; + } + + Real value3 = ((Real)0.5)*value1*invValue0; + for (i1 = 0; i1 <= i3; ++i1) + { + value1 = mMatrix[i0][i1]; + value2 = mSubdiagonal[i1] - value3*value1; + mSubdiagonal[i1] = value2; + for (i2 = 0; i2 <= i1; i2++) + { + mMatrix[i1][i2] -= + value1*mSubdiagonal[i2] + value2*mMatrix[i0][i2]; + } + } + } + } + else + { + mSubdiagonal[i0] = mMatrix[i0][i3]; + } + + mDiagonal[i0] = value0; + } + + mDiagonal[0] = (Real)0; + mSubdiagonal[0] = (Real)0; + for (i0 = 0, i3 = -1; i0 <= mSize - 1; ++i0, ++i3) + { + if (mDiagonal[i0] != (Real)0) + { + for (i1 = 0; i1 <= i3; ++i1) + { + Real sum = (Real)0; + for (i2 = 0; i2 <= i3; ++i2) + { + sum += mMatrix[i0][i2]*mMatrix[i2][i1]; + } + for (i2 = 0; i2 <= i3; ++i2) + { + mMatrix[i2][i1] -= sum*mMatrix[i2][i0]; + } + } + } + mDiagonal[i0] = mMatrix[i0][i0]; + mMatrix[i0][i0] = (Real)1; + for (i1 = 0; i1 <= i3; ++i1) + { + mMatrix[i1][i0] = (Real)0; + mMatrix[i0][i1] = (Real)0; + } + } + + // Reordering needed by EigenDecomposition::QLAlgorithm. + for (i0 = 1, i3 = 0; i0 < mSize; ++i0, ++i3) + { + mSubdiagonal[i3] = mSubdiagonal[i0]; + } + mSubdiagonal[mSize-1] = (Real)0; + + mIsRotation = ((mSize % 2) == 0); +} +//---------------------------------------------------------------------------- +template +bool EigenDecomposition::QLAlgorithm () +{ + // TODO: This is Numerical Recipes in C code. Rewrite to avoid + // copyright issues. + + const int iMaxIter = 32; + + for (int i0 = 0; i0 < mSize; ++i0) + { + int i1; + for (i1 = 0; i1 < iMaxIter; ++i1) + { + int i2; + for (i2 = i0; i2 <= mSize - 2; ++i2) + { + Real tmp = Math::FAbs(mDiagonal[i2]) + + Math::FAbs(mDiagonal[i2+1]); + + if (Math::FAbs(mSubdiagonal[i2]) + tmp == tmp) + { + break; + } + } + if (i2 == i0) + { + break; + } + + Real value0 = (mDiagonal[i0 + 1] + - mDiagonal[i0])/(((Real)2)*mSubdiagonal[i0]); + Real value1 = Math::Sqrt(value0*value0 + (Real)1); + if (value0 < (Real)0) + { + value0 = mDiagonal[i2] - mDiagonal[i0] + + mSubdiagonal[i0]/(value0 - value1); + } + else + { + value0 = mDiagonal[i2] - mDiagonal[i0] + + mSubdiagonal[i0]/(value0 + value1); + } + + Real sn = (Real)1, cs = (Real)1, value2 = (Real)0; + for (int i3 = i2 - 1; i3 >= i0; --i3) + { + Real value3 = sn*mSubdiagonal[i3]; + Real value4 = cs*mSubdiagonal[i3]; + if (Math::FAbs(value3) >= Math::FAbs(value0)) + { + cs = value0/value3; + value1 = Math::Sqrt(cs*cs + (Real)1); + mSubdiagonal[i3 + 1] = value3*value1; + sn = ((Real)1)/value1; + cs *= sn; + } + else + { + sn = value3/value0; + value1 = Math::Sqrt(sn*sn + (Real)1); + mSubdiagonal[i3 + 1] = value0*value1; + cs = ((Real)1)/value1; + sn *= cs; + } + value0 = mDiagonal[i3 + 1] - value2; + value1 = (mDiagonal[i3] - value0)*sn + ((Real)2)*value4*cs; + value2 = sn*value1; + mDiagonal[i3 + 1] = value0 + value2; + value0 = cs*value1 - value4; + + for (int i4 = 0; i4 < mSize; ++i4) + { + value3 = mMatrix[i4][i3 + 1]; + mMatrix[i4][i3 + 1] = sn*mMatrix[i4][i3] + cs*value3; + mMatrix[i4][i3] = cs*mMatrix[i4][i3] - sn*value3; + } + } + mDiagonal[i0] -= value2; + mSubdiagonal[i0] = value0; + mSubdiagonal[i2] = (Real)0; + } + if (i1 == iMaxIter) + { + return false; + } + } + + return true; +} +//---------------------------------------------------------------------------- +template +void EigenDecomposition::DecreasingSort () +{ + // Sort the eigenvalues in decreasing order, e[0] >= ... >= e[mSize-1] + for (int i0 = 0, i1; i0 <= mSize - 2; ++i0) + { + // Locate the maximum eigenvalue. + i1 = i0; + Real maxValue = mDiagonal[i1]; + int i2; + for (i2 = i0 + 1; i2 < mSize; ++i2) + { + if (mDiagonal[i2] > maxValue) + { + i1 = i2; + maxValue = mDiagonal[i1]; + } + } + + if (i1 != i0) + { + // Swap the eigenvalues. + mDiagonal[i1] = mDiagonal[i0]; + mDiagonal[i0] = maxValue; + + // Swap the eigenvectors corresponding to the eigenvalues. + for (i2 = 0; i2 < mSize; ++i2) + { + Real tmp = mMatrix[i2][i0]; + mMatrix[i2][i0] = mMatrix[i2][i1]; + mMatrix[i2][i1] = tmp; + mIsRotation = !mIsRotation; + } + } + } +} +//---------------------------------------------------------------------------- +template +void EigenDecomposition::IncreasingSort () +{ + // Sort the eigenvalues in increasing order, e[0] <= ... <= e[mSize-1] + for (int i0 = 0, i1; i0 <= mSize - 2; ++i0) + { + // Locate the minimum eigenvalue. + i1 = i0; + Real minValue = mDiagonal[i1]; + int i2; + for (i2 = i0 + 1; i2 < mSize; ++i2) + { + if (mDiagonal[i2] < minValue) + { + i1 = i2; + minValue = mDiagonal[i1]; + } + } + + if (i1 != i0) + { + // Swap the eigenvalues. + mDiagonal[i1] = mDiagonal[i0]; + mDiagonal[i0] = minValue; + + // Swap the eigenvectors corresponding to the eigenvalues. + for (i2 = 0; i2 < mSize; ++i2) + { + Real tmp = mMatrix[i2][i0]; + mMatrix[i2][i0] = mMatrix[i2][i1]; + mMatrix[i2][i1] = tmp; + mIsRotation = !mIsRotation; + } + } + } +} +//---------------------------------------------------------------------------- +template +void EigenDecomposition::GuaranteeRotation () +{ + if (!mIsRotation) + { + // Change sign on the first column. + for (int row = 0; row < mSize; ++row) + { + mMatrix[row][0] = -mMatrix[row][0]; + } + } +} +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +// Explicit instantiation. +//---------------------------------------------------------------------------- +template WM5_MATHEMATICS_ITEM +class EigenDecomposition; + +template WM5_MATHEMATICS_ITEM +class EigenDecomposition; + +//---------------------------------------------------------------------------- +template +Line3 OrthogonalLineFit3 (int numPoints, const Vector3* points) +{ + Line3 line(Vector3(3), Vector3(3)); + + // Compute the mean of the points. + line.Origin = points[0]; + int i; + for (i = 1; i < numPoints; i++) + { + line.Origin += points[i]; + } + Real invNumPoints = ((Real)1)/numPoints; + line.Origin *= invNumPoints; + + // Compute the covariance matrix of the points. + Real sumXX = (Real)0, sumXY = (Real)0, sumXZ = (Real)0; + Real sumYY = (Real)0, sumYZ = (Real)0, sumZZ = (Real)0; + for (i = 0; i < numPoints; i++) + { + Vector3 diff = points[i] - line.Origin; + sumXX += diff[0]*diff[0]; + sumXY += diff[0]*diff[1]; + sumXZ += diff[0]*diff[2]; + sumYY += diff[1]*diff[1]; + sumYZ += diff[1]*diff[2]; + sumZZ += diff[2]*diff[2]; + } + + sumXX *= invNumPoints; + sumXY *= invNumPoints; + sumXZ *= invNumPoints; + sumYY *= invNumPoints; + sumYZ *= invNumPoints; + sumZZ *= invNumPoints; + + // Set up the eigensolver. + EigenDecomposition esystem(3); + esystem(0,0) = sumYY+sumZZ; + esystem(0,1) = -sumXY; + esystem(0,2) = -sumXZ; + esystem(1,0) = esystem(0,1); + esystem(1,1) = sumXX+sumZZ; + esystem(1,2) = -sumYZ; + esystem(2,0) = esystem(0,2); + esystem(2,1) = esystem(1,2); + esystem(2,2) = sumXX+sumYY; + + // Compute eigenstuff, smallest eigenvalue is in last position. + esystem.Solve(false); + + // Unit-length direction for best-fit line. + line.Direction = esystem.GetEigenvector(2); + + return line; +} +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +// Explicit instantiation. +//---------------------------------------------------------------------------- +template WM5_MATHEMATICS_ITEM +Line3 OrthogonalLineFit3 (int, const Vector3*); + +template WM5_MATHEMATICS_ITEM +Line3 OrthogonalLineFit3 (int, const Vector3*); +//---------------------------------------------------------------------------- + + + +} // namespace diff --git a/tjp/core/math/detail/Wm5.h b/tjp/core/math/detail/Wm5.h new file mode 100644 index 0000000..8162955 --- /dev/null +++ b/tjp/core/math/detail/Wm5.h @@ -0,0 +1,355 @@ +// +// Wm5.h +// algorithm +// +// Created by Timothy Prepscius on 5/3/18. +// Copyright © 2018 Timothy Prepscius. All rights reserved. +// + +#pragma once + +#include +#include +#include + +namespace Wm5 { + +#define WM5_MATHEMATICS_ITEM +#define assertion(...) + +template +T *new1(size_t size) +{ + return new T[size]; +} + +template +void delete1(T *t) +{ + delete[] t; +} + +// ----- + +template +struct Math +{ + WM5_MATHEMATICS_ITEM static const Real ZERO_TOLERANCE; + + static Real FAbs (Real value); + static Real Sqrt (Real value); +} ; + +typedef Math Mathf; +typedef Math Mathd; + +// ----- + +template +class GVector +{ +public: + // Construction and destruction. + GVector (int size = 0); + GVector (int size, const Real* tuple); + GVector (const GVector& vec); + ~GVector (); + + // Coordinate access. + void SetSize (int size); + inline int GetSize () const; + inline operator const Real* () const; + inline operator Real* (); + inline const Real& operator[] (int i) const; + inline Real& operator[] (int i); + + // Assignment. + GVector& operator= (const GVector& vec); + + // Comparison (for use by STL containers). + bool operator== (const GVector& vec) const; + bool operator!= (const GVector& vec) const; + bool operator< (const GVector& vec) const; + bool operator<= (const GVector& vec) const; + bool operator> (const GVector& vec) const; + bool operator>= (const GVector& vec) const; + + // Arithmetic operations. + GVector operator+ (const GVector& vec) const; + GVector operator- (const GVector& vec) const; + GVector operator* (Real scalar) const; + GVector operator/ (Real scalar) const; + GVector operator- () const; + + friend GVector operator* (Real scalar, const GVector& vec) + { + return vec*scalar; + } + + // Arithmetic updates. + GVector& operator+= (const GVector& vec); + GVector& operator-= (const GVector& vec); + GVector& operator*= (Real scalar); + GVector& operator/= (Real scalar); + + // Vector operations. + Real Length () const; + Real SquaredLength () const; + Real Dot (const GVector& vec) const; + Real Normalize (Real epsilon = Math::ZERO_TOLERANCE); + +protected: + int mSize; + Real* mTuple; +}; + +typedef GVector GVectorf; +typedef GVector GVectord; + +// ----- + +template +class GMatrix +{ +public: + // Construction and destruction. + GMatrix (int rows = 0, int columns = 0); + GMatrix (int rows, int columns, const Real* entry); + GMatrix (int rows, int columns, const Real** matrix); + GMatrix (const GMatrix& mat); + ~GMatrix (); + + // Coordinate access. + void SetSize (int rows, int columns); + inline void GetSize (int& rows, int& columns) const; + inline int GetRows () const; + inline int GetColumns () const; + inline int GetQuantity () const; + inline operator const Real* () const; + inline operator Real* (); + inline const Real* operator[] (int row) const; + inline Real* operator[] (int row); + inline const Real& operator() (int row, int column) const; + inline Real& operator() (int row, int column); + void SwapRows (int row0, int row1); + void SetRow (int row, const GVector& vec); + GVector GetRow (int row) const; + void SetColumn (int column, const GVector& vec); + GVector GetColumn (int column) const; + void SetMatrix (int rows, int columns, const Real* entry); + void SetMatrix (int rows, int columns, const Real** matrix); + void GetColumnMajor (Real* columnMajor) const; + + // Assignment. + GMatrix& operator= (const GMatrix& mat); + + // Comparison (for use by STL containers). + bool operator== (const GMatrix& mat) const; + bool operator!= (const GMatrix& mat) const; + bool operator< (const GMatrix& mat) const; + bool operator<= (const GMatrix& mat) const; + bool operator> (const GMatrix& mat) const; + bool operator>= (const GMatrix& mat) const; + + // Arithmetic operations. + GMatrix operator+ (const GMatrix& mat) const; + GMatrix operator- (const GMatrix& mat) const; + GMatrix operator* (const GMatrix& mat) const; + GMatrix operator* (Real fScalar) const; + GMatrix operator/ (Real fScalar) const; + GMatrix operator- () const; + + // Arithmetic updates. + GMatrix& operator+= (const GMatrix& mat); + GMatrix& operator-= (const GMatrix& mat); + GMatrix& operator*= (Real fScalar); + GMatrix& operator/= (Real fScalar); + + // M*vec + GVector operator* (const GVector& vec) const; + + // u^T*M*v + Real QForm (const GVector& u, const GVector& v) const; + + // M^T + GMatrix Transpose () const; + + // M^T*mat + GMatrix TransposeTimes (const GMatrix& mat) const; + + // M*mat^T + GMatrix TimesTranspose (const GMatrix& mat) const; + + // M^T*mat^T + GMatrix TransposeTimesTranspose (const GMatrix& mat) const; + + // Inversion. The matrix must be square. The function returns 'true' + // whenever the matrix is square and invertible. + bool GetInverse (GMatrix& inverse) const; + + // c * M + friend GMatrix operator* (Real scalar, const GMatrix& mat) + { + return mat*scalar; + } + + // v^T * M + friend GVector operator* (const GVector& vec, + const GMatrix& mat) + { + assertion(vec.GetSize() == mat.GetRows(), "Mismatch in operator*\n"); + GVector prod(mat.GetColumns()); + Real* entry = prod; + for (int c = 0; c < mat.GetColumns(); ++c) + { + for (int r = 0; r < mat.GetRows(); ++r) + { + entry[c] += vec[r]*mat[r][c]; + } + } + return prod; + } + +protected: + // Support for allocation and deallocation. The allocation call requires + // m_iRows, m_iCols, and m_iQuantity to have already been correctly + // initialized. + void Allocate (bool setToZero); + void Deallocate (); + + int mRows, mColumns, mQuantity; + + // The matrix is stored in row-major form as a 1-dimensional array. + Real* mData; + + // An array of pointers to the rows of the matrix. The separation of + // row pointers and actual data supports swapping of rows in linear + // algebraic algorithms such as solving linear systems of equations. + Real** mEntry; +}; + + +typedef GMatrix GMatrixf; +typedef GMatrix GMatrixd; + +// ----- + + +template +class WM5_MATHEMATICS_ITEM EigenDecomposition +{ +public: + // Construction and destruction. The matrix of an eigensystem must be + // symmetric. + EigenDecomposition (int size); +// EigenDecomposition (const Matrix2& mat); +// EigenDecomposition (const Matrix3& mat); + EigenDecomposition (const GMatrix& mat); + ~EigenDecomposition (); + + // Set the matrix for the eigensystem. + Real& operator() (int row, int column); +// EigenDecomposition& operator= (const Matrix2& mat); +// EigenDecomposition& operator= (const Matrix3& mat); + EigenDecomposition& operator= (const GMatrix& mat); + + // Solve the eigensystem. Set 'increasingSort' to 'true' when you want + // the eigenvalues to be sorted in increasing order; otherwise, the + // eigenvalues are sorted in decreasing order. + void Solve (bool increasingSort); + + // Get the results. The calls to GetEigenvector2, GetEigenvectors2, + // GetEigenvector3, and GetEigenvector3 should be made only if you know + // that the eigensystem is of the corresponding size. + Real GetEigenvalue (int i) const; + const Real* GetEigenvalues () const; +// Vector2 GetEigenvector2 (int i) const; +// Matrix2 GetEigenvectors2 () const; +// Vector3 GetEigenvector3 (int i) const; +// Matrix3 GetEigenvectors3 () const; + GVector GetEigenvector (int i) const; + const GMatrix& GetEigenvectors () const; + +private: + int mSize; + GMatrix mMatrix; + Real* mDiagonal; + Real* mSubdiagonal; + + // For odd size matrices, the Householder reduction involves an odd + // number of reflections. The product of these is a reflection. The + // QL algorithm uses rotations for further reductions. The final + // orthogonal matrix whose columns are the eigenvectors is a reflection, + // so its determinant is -1. For even size matrices, the Householder + // reduction involves an even number of reflections whose product is a + // rotation. The final orthogonal matrix has determinant +1. Many + // algorithms that need an eigendecomposition want a rotation matrix. + // We want to guarantee this is the case, so mRotation keeps track of + // this. The DecrSort and IncrSort further complicate the issue since + // they swap columns of the orthogonal matrix, causing the matrix to + // toggle between rotation and reflection. The value mRotation must + // be toggled accordingly. + bool mIsRotation; + void GuaranteeRotation (); + + // Householder reduction to tridiagonal form. + void Tridiagonal2 (); + void Tridiagonal3 (); + void TridiagonalN (); + + // QL algorithm with implicit shifting. This function is called for + // tridiagonal matrices. + bool QLAlgorithm (); + + // Sort eigenvalues from largest to smallest. + void DecreasingSort (); + + // Sort eigenvalues from smallest to largest. + void IncreasingSort (); +}; + +typedef EigenDecomposition EigenDecompositionf; +typedef EigenDecomposition EigenDecompositiond; + + +// ----- + +template +using Vector3 = GVector; + +template +class Line3 +{ +public: + // The line is represented as P+t*D where P is the line origin, D is a + // unit-length direction vector, and t is any real number. The user must + // ensure that D is indeed unit length. + + // Construction and destruction. + Line3 () {}; // uninitialized + ~Line3 () {}; + + Line3 (const Vector3& origin, const Vector3& direction) : + Origin(origin), + Direction(direction) + { + } + + Vector3 Origin, Direction; +}; + +typedef Line3 Line3f; +typedef Line3 Line3d; + +// ------- + +// Least-squares fit of a line to (x,y,z) data by using distance measurements +// orthogonal to the proposed line. +template WM5_MATHEMATICS_ITEM +Line3 OrthogonalLineFit3 (int numPoints, const Vector3* points); + +// ------ + +#include "Wm5.inl" + +} // namespace diff --git a/tjp/core/math/detail/Wm5.inl b/tjp/core/math/detail/Wm5.inl new file mode 100644 index 0000000..d3ce7d5 --- /dev/null +++ b/tjp/core/math/detail/Wm5.inl @@ -0,0 +1,1089 @@ +// +// Wm5.inl +// algorithm +// +// Created by Timothy Prepscius on 5/3/18. +// Copyright © 2018 Timothy Prepscius. All rights reserved. +// + + + +//---------------------------------------------------------------------------- +template +Real Math::FAbs (Real value) +{ + return fabs(value); +} +//---------------------------------------------------------------------------- +template +Real Math::Sqrt (Real value) +{ + if (value >= (Real)0) + { + return sqrt(value); + } + else + { + assertion(false, "Negative input to Sqrt\n"); + return (Real)0; + } +} + + +/**************************************************************************/ + +//---------------------------------------------------------------------------- +template +GVector::GVector (int size) +{ + if (size > 0) + { + mSize = size; + mTuple = new1(mSize); + size_t numBytes = mSize*sizeof(Real); + memset(mTuple, 0, numBytes); + } + else + { + mSize = 0; + mTuple = 0; + } +} +//---------------------------------------------------------------------------- +template +GVector::GVector (int size, const Real* tuple) +{ + if (size > 0) + { + mSize = size; + mTuple = new1(mSize); + size_t numBytes = mSize*sizeof(Real); + memcpy(mTuple, tuple, numBytes); + } + else + { + mSize = 0; + mTuple = 0; + } +} +//---------------------------------------------------------------------------- +template +GVector::GVector (const GVector& vec) +{ + mSize = vec.mSize; + if (mSize > 0) + { + mTuple = new1(mSize); + size_t numBytes = mSize*sizeof(Real); + memcpy(mTuple, vec.mTuple, numBytes); + } + else + { + mTuple = 0; + } +} +//---------------------------------------------------------------------------- +template +GVector::~GVector () +{ + delete1(mTuple); +} +//---------------------------------------------------------------------------- +template +void GVector::SetSize (int size) +{ + delete1(mTuple); + if (size > 0) + { + mSize = size; + mTuple = new1(mSize); + size_t numBytes = mSize*sizeof(Real); + memset(mTuple, 0, numBytes); + } + else + { + mSize = 0; + mTuple = 0; + } +} +//---------------------------------------------------------------------------- +template +inline int GVector::GetSize () const +{ + return mSize; +} +//---------------------------------------------------------------------------- +template +inline GVector::operator const Real* () const +{ + return mTuple; +} +//---------------------------------------------------------------------------- +template +inline GVector::operator Real* () +{ + return mTuple; +} +//---------------------------------------------------------------------------- +template +inline const Real& GVector::operator[] (int i) const +{ + assertion(0 <= i && i < mSize, "Invalid index in operator[]\n"); + return mTuple[i]; +} +//---------------------------------------------------------------------------- +template +inline Real& GVector::operator[] (int i) +{ + assertion(0 <= i && i < mSize, "Invalid index in operator[]\n"); + return mTuple[i]; +} +//---------------------------------------------------------------------------- +template +GVector& GVector::operator= (const GVector& vec) +{ + if (vec.mSize > 0) + { + if (mSize != vec.mSize) + { + delete1(mTuple); + mSize = vec.mSize; + mTuple = new1(mSize); + } + size_t numBytes = mSize*sizeof(Real); + memcpy(mTuple, vec.mTuple, numBytes); + } + else + { + delete1(mTuple); + mSize = 0; + mTuple = 0; + } + return *this; +} +//---------------------------------------------------------------------------- +template +bool GVector::operator== (const GVector& vec) const +{ + return memcmp(mTuple, vec.mTuple, mSize*sizeof(Real)) == 0; +} +//---------------------------------------------------------------------------- +template +bool GVector::operator!= (const GVector& vec) const +{ + return memcmp(mTuple, vec.mTuple, mSize*sizeof(Real)) != 0; +} +//---------------------------------------------------------------------------- +template +bool GVector::operator< (const GVector& vec) const +{ + return memcmp(mTuple, vec.mTuple, mSize*sizeof(Real)) < 0; +} +//---------------------------------------------------------------------------- +template +bool GVector::operator<= (const GVector& vec) const +{ + return memcmp(mTuple, vec.mTuple, mSize*sizeof(Real)) <= 0; +} +//---------------------------------------------------------------------------- +template +bool GVector::operator> (const GVector& vec) const +{ + return memcmp(mTuple, vec.mTuple, mSize*sizeof(Real)) > 0; +} +//---------------------------------------------------------------------------- +template +bool GVector::operator>= (const GVector& vec) const +{ + return memcmp(mTuple, vec.mTuple, mSize*sizeof(Real)) >= 0; +} +//---------------------------------------------------------------------------- +template +GVector GVector::operator+ (const GVector& vec) const +{ + GVector result(mSize); + for (int i = 0; i < mSize; ++i) + { + result.mTuple[i] = mTuple[i] + vec.mTuple[i]; + } + return result; +} +//---------------------------------------------------------------------------- +template +GVector GVector::operator- (const GVector& vec) const +{ + GVector result(mSize); + for (int i = 0; i < mSize; ++i) + { + result.mTuple[i] = mTuple[i] - vec.mTuple[i]; + } + return result; +} +//---------------------------------------------------------------------------- +template +GVector GVector::operator* (Real scalar) const +{ + GVector result(mSize); + for (int i = 0; i < mSize; ++i) + { + result.mTuple[i] = scalar*mTuple[i]; + } + return result; +} +//---------------------------------------------------------------------------- +template +GVector GVector::operator/ (Real scalar) const +{ + GVector result(mSize); + int i; + + if (scalar != (Real)0) + { + Real invScalar = ((Real)1)/scalar; + for (i = 0; i < mSize; ++i) + { + result.mTuple[i] = invScalar*mTuple[i]; + } + } + else + { + for (i = 0; i < mSize; ++i) + { + result.mTuple[i] = Math::MAX_REAL; + } + } + + return result; +} +//---------------------------------------------------------------------------- +template +GVector GVector::operator- () const +{ + GVector result(mSize); + for (int i = 0; i < mSize; ++i) + { + result.mTuple[i] = -mTuple[i]; + } + return result; +} +//---------------------------------------------------------------------------- +template +GVector& GVector::operator+= (const GVector& vec) +{ + for (int i = 0; i < mSize; ++i) + { + mTuple[i] += vec.mTuple[i]; + } + return *this; +} +//---------------------------------------------------------------------------- +template +GVector& GVector::operator-= (const GVector& vec) +{ + for (int i = 0; i < mSize; ++i) + { + mTuple[i] -= vec.mTuple[i]; + } + return *this; +} +//---------------------------------------------------------------------------- +template +GVector& GVector::operator*= (Real scalar) +{ + for (int i = 0; i < mSize; ++i) + { + mTuple[i] *= scalar; + } + return *this; +} +//---------------------------------------------------------------------------- +template +GVector& GVector::operator/= (Real scalar) +{ + int i; + + if (scalar != (Real)0) + { + Real invScalar = ((Real)1)/scalar; + for (i = 0; i < mSize; ++i) + { + mTuple[i] *= invScalar; + } + } + else + { + for (i = 0; i < mSize; ++i) + { + mTuple[i] = Math::MAX_REAL; + } + } + + return *this; +} +//---------------------------------------------------------------------------- +template +Real GVector::Length () const +{ + Real sqrLength = (Real)0; + for (int i = 0; i < mSize; ++i) + { + sqrLength += mTuple[i]*mTuple[i]; + } + return Math::Sqrt(sqrLength); +} +//---------------------------------------------------------------------------- +template +Real GVector::SquaredLength () const +{ + Real sqrLength = (Real)0; + for (int i = 0; i < mSize; ++i) + { + sqrLength += mTuple[i]*mTuple[i]; + } + return sqrLength; +} +//---------------------------------------------------------------------------- +template +Real GVector::Dot (const GVector& vec) const +{ + Real dotProduct = (Real)0; + for (int i = 0; i < mSize; ++i) + { + dotProduct += mTuple[i]*vec.mTuple[i]; + } + return dotProduct; +} +//---------------------------------------------------------------------------- +template +Real GVector::Normalize (Real epsilon) +{ + Real length = Length(); + int i; + + if (length > epsilon) + { + Real invLength = ((Real)1)/length; + for (i = 0; i < mSize; ++i) + { + mTuple[i] *= invLength; + } + } + else + { + length = (Real)0; + for (i = 0; i < mSize; ++i) + { + mTuple[i] = (Real)0; + } + } + + return length; +} +//---------------------------------------------------------------------------- + +/****************************************************************************/ + +//---------------------------------------------------------------------------- +template +GMatrix::GMatrix (int rows, int columns) +{ + mData = 0; + mEntry = 0; + SetSize(rows, columns); +} +//---------------------------------------------------------------------------- +template +GMatrix::GMatrix (int rows, int columns, const Real* entry) +{ + mData = 0; + mEntry = 0; + SetMatrix(rows, columns, entry); +} +//---------------------------------------------------------------------------- +template +GMatrix::GMatrix (int rows, int columns, const Real** matrix) +{ + mData = 0; + mEntry = 0; + SetMatrix(rows, columns, matrix); +} +//---------------------------------------------------------------------------- +template +GMatrix::GMatrix (const GMatrix& mat) +{ + mRows = 0; + mColumns = 0; + mQuantity = 0; + mData = 0; + mEntry = 0; + *this = mat; +} +//---------------------------------------------------------------------------- +template +GMatrix::~GMatrix () +{ + Deallocate(); +} +//---------------------------------------------------------------------------- +template +void GMatrix::SetSize (int rows, int columns) +{ + Deallocate(); + if (rows > 0 && columns > 0) + { + mRows = rows; + mColumns = columns; + mQuantity = mRows*mColumns; + Allocate(true); + } + else + { + mRows = 0; + mColumns = 0; + mQuantity = 0; + mData = 0; + mEntry = 0; + } +} +//---------------------------------------------------------------------------- +template +inline void GMatrix::GetSize (int& rows, int& columns) const +{ + rows = mRows; + columns = mColumns; +} +//---------------------------------------------------------------------------- +template +inline int GMatrix::GetRows () const +{ + return mRows; +} +//---------------------------------------------------------------------------- +template +inline int GMatrix::GetColumns () const +{ + return mColumns; +} +//---------------------------------------------------------------------------- +template +inline int GMatrix::GetQuantity () const +{ + return mQuantity; +} +//---------------------------------------------------------------------------- +template +inline GMatrix::operator const Real* () const +{ + return mData; +} +//---------------------------------------------------------------------------- +template +inline GMatrix::operator Real* () +{ + return mData; +} +//---------------------------------------------------------------------------- +template +inline const Real* GMatrix::operator[] (int row) const +{ + assertion(0 <= row && row < mRows, "Invalid index in operator[]\n"); + return mEntry[row]; +} +//---------------------------------------------------------------------------- +template +inline Real* GMatrix::operator[] (int row) +{ + assertion(0 <= row && row < mRows, "Invalid index in operator[]\n"); + return mEntry[row]; +} +//---------------------------------------------------------------------------- +template +inline const Real& GMatrix::operator() (int row, int column) const +{ + return mEntry[row][column]; +} +//---------------------------------------------------------------------------- +template +inline Real& GMatrix::operator() (int row, int column) +{ + assertion(0 <= row && row < mRows && 0 <= column && + column <= mColumns, "Invalid index in operator()\n"); + + return mEntry[row][column]; +} +//---------------------------------------------------------------------------- +template +void GMatrix::SwapRows (int row0, int row1) +{ + assertion(0 <= row0 && row0 < mRows && 0 <= row1 && row1 < mRows, + "Invalid index in SwapRows\n"); + + Real* save = mEntry[row0]; + mEntry[row0] = mEntry[row1]; + mEntry[row1] = save; +} +//---------------------------------------------------------------------------- +template +void GMatrix::SetRow (int row, const GVector& vec) +{ + assertion(0 <= row && row < mRows && vec.GetSize() == mColumns, + "Invalid index in SetRow\n"); + + for (int c = 0; c < mColumns; ++c) + { + mEntry[row][c] = vec[c]; + } +} +//---------------------------------------------------------------------------- +template +GVector GMatrix::GetRow (int row) const +{ + assertion(0 <= row && row < mRows, "Invalid index in SetRow\n"); + + GVector vec(mColumns); + for (int c = 0; c < mColumns; ++c) + { + vec[c] = mEntry[row][c]; + } + return vec; +} +//---------------------------------------------------------------------------- +template +void GMatrix::SetColumn (int column, const GVector& vec) +{ + assertion(0 <= column && column < mColumns && vec.GetSize() == mRows, + "Invalid index in SetColumn\n"); + + for (int r = 0; r < mRows; ++r) + { + mEntry[r][column] = vec[r]; + } +} +//---------------------------------------------------------------------------- +template +GVector GMatrix::GetColumn (int column) const +{ + assertion(0 <= column && column < mColumns, + "Invalid index in GetColumn\n"); + + GVector vec(mRows); + for (int r = 0; r < mRows; ++r) + { + vec[r] = mEntry[r][column]; + } + return vec; +} +//---------------------------------------------------------------------------- +template +void GMatrix::SetMatrix (int rows, int columns, const Real* entry) +{ + Deallocate(); + if (rows > 0 && columns > 0) + { + mRows = rows; + mColumns = columns; + mQuantity = mRows*mColumns; + Allocate(false); + size_t numBytes = mQuantity*sizeof(Real); + memcpy(mData, entry, numBytes); + } + else + { + mRows = 0; + mColumns = 0; + mQuantity = 0; + mData = 0; + mEntry = 0; + } +} +//---------------------------------------------------------------------------- +template +void GMatrix::SetMatrix (int rows, int columns, const Real** matrix) +{ + Deallocate(); + if (rows > 0 && columns > 0) + { + mRows = rows; + mColumns = columns; + mQuantity = mRows*mColumns; + Allocate(false); + for (int r = 0; r < mRows; ++r) + { + for (int c = 0; c < mColumns; ++c) + { + mEntry[r][c] = matrix[r][c]; + } + } + } + else + { + mRows = 0; + mColumns = 0; + mQuantity = 0; + mData = 0; + mEntry = 0; + } +} +//---------------------------------------------------------------------------- +template +void GMatrix::GetColumnMajor (Real* columnMajor) const +{ + for (int r = 0, i = 0; r < mRows; ++r) + { + for (int c = 0; c < mColumns; ++c, ++i) + { + columnMajor[i] = mEntry[c][r]; + } + } +} +//---------------------------------------------------------------------------- +template +GMatrix& GMatrix::operator= (const GMatrix& mat) +{ + if (mat.mQuantity > 0) + { + if (mRows != mat.mRows || mColumns != mat.mColumns) + { + Deallocate(); + mRows = mat.mRows; + mColumns = mat.mColumns; + mQuantity = mat.mQuantity; + Allocate(false); + } + for (int r = 0; r < mRows; ++r) + { + for (int c = 0; c < mColumns; ++c) + { + mEntry[r][c] = mat.mEntry[r][c]; + } + } + } + else + { + Deallocate(); + mRows = 0; + mColumns = 0; + mQuantity = 0; + mData = 0; + mEntry = 0; + } + return *this; +} +//---------------------------------------------------------------------------- +template +bool GMatrix::operator== (const GMatrix& mat) const +{ + return memcmp(mData, mat.mData, mQuantity*sizeof(Real)) == 0; +} +//---------------------------------------------------------------------------- +template +bool GMatrix::operator!= (const GMatrix& mat) const +{ + return memcmp(mData, mat.mData, mQuantity*sizeof(Real)) != 0; +} +//---------------------------------------------------------------------------- +template +bool GMatrix::operator< (const GMatrix& mat) const +{ + return memcmp(mData, mat.mData, mQuantity*sizeof(Real)) < 0; +} +//---------------------------------------------------------------------------- +template +bool GMatrix::operator<= (const GMatrix& mat) const +{ + return memcmp(mData, mat.mData, mQuantity*sizeof(Real)) <= 0; +} +//---------------------------------------------------------------------------- +template +bool GMatrix::operator> (const GMatrix& mat) const +{ + return memcmp(mData, mat.mData, mQuantity*sizeof(Real)) > 0; +} +//---------------------------------------------------------------------------- +template +bool GMatrix::operator>= (const GMatrix& mat) const +{ + return memcmp(mData, mat.mData, mQuantity*sizeof(Real)) >= 0; +} +//---------------------------------------------------------------------------- +template +GMatrix GMatrix::operator+ (const GMatrix& mat) const +{ + GMatrix result(mat.mRows, mat.mColumns); + for (int i = 0; i < mQuantity; ++i) + { + result.mData[i] = mData[i] + mat.mData[i]; + } + return result; +} +//---------------------------------------------------------------------------- +template +GMatrix GMatrix::operator- (const GMatrix& mat) const +{ + GMatrix result(mat.mRows, mat.mColumns); + for (int i = 0; i < mQuantity; ++i) + { + result.mData[i] = mData[i] - mat.mData[i]; + } + return result; +} +//---------------------------------------------------------------------------- +template +GMatrix GMatrix::operator* (const GMatrix& mat) const +{ + // 'this' is RxN, 'M' is NxC, 'product = this*M' is RxC + assertion(mColumns == mat.mRows, "Mismatch in operator*\n"); + + GMatrix result(mRows, mat.mColumns); + for (int r = 0; r < result.mRows; ++r) + { + for (int c = 0; c < result.mColumns; ++c) + { + for (int m = 0; m < mColumns; ++m) + { + result.mEntry[r][c] += mEntry[r][m] * mat.mEntry[m][c]; + } + } + } + return result; +} +//---------------------------------------------------------------------------- +template +GMatrix GMatrix::operator* (Real scalar) const +{ + GMatrix result(mRows, mColumns); + for (int i = 0; i < mQuantity; ++i) + { + result.mData[i] = scalar*mData[i]; + } + return result; +} +//---------------------------------------------------------------------------- +template +GMatrix GMatrix::operator/ (Real scalar) const +{ + GMatrix result(mRows, mColumns); + int i; + + if (scalar != (Real)0) + { + Real invScalar = ((Real)1)/scalar; + for (i = 0; i < mQuantity; ++i) + { + result.mData[i] = invScalar*mData[i]; + } + } + else + { + for (i = 0; i < mQuantity; ++i) + { + result.mData[i] = Math::MAX_REAL; + } + } + + return result; +} +//---------------------------------------------------------------------------- +template +GMatrix GMatrix::operator- () const +{ + GMatrix result(mRows, mColumns); + for (int i = 0; i < mQuantity; ++i) + { + result.mData[i] = -mData[i]; + } + return result; +} +//---------------------------------------------------------------------------- +template +GMatrix& GMatrix::operator+= (const GMatrix& mat) +{ + for (int i = 0; i < mQuantity; ++i) + { + mData[i] += mat.mData[i]; + } + return *this; +} +//---------------------------------------------------------------------------- +template +GMatrix& GMatrix::operator-= (const GMatrix& mat) +{ + for (int i = 0; i < mQuantity; ++i) + { + mData[i] -= mat.mData[i]; + } + return *this; +} +//---------------------------------------------------------------------------- +template +GMatrix& GMatrix::operator*= (Real scalar) +{ + for (int i = 0; i < mQuantity; ++i) + { + mData[i] *= scalar; + } + return *this; +} +//---------------------------------------------------------------------------- +template +GMatrix& GMatrix::operator/= (Real scalar) +{ + int i; + + if (scalar != (Real)0) + { + Real invScalar = ((Real)1)/scalar; + for (i = 0; i < mQuantity; ++i) + { + mData[i] *= invScalar; + } + } + else + { + for (i = 0; i < mQuantity; ++i) + { + mData[i] = Math::MAX_REAL; + } + } + + return *this; +} +//---------------------------------------------------------------------------- +template +GVector GMatrix::operator* (const GVector& vec) const +{ + assertion(vec.GetSize() == mColumns, "Mismatch in operator*\n"); + + GVector result(mRows); + for (int r = 0; r < mRows; ++r) + { + for (int c = 0; c < mColumns; ++c) + { + result[r] += mEntry[r][c]*vec[c]; + } + + } + return result; +} +//---------------------------------------------------------------------------- +template +Real GMatrix::QForm (const GVector& u, const GVector& v) + const +{ + assertion(u.GetSize() == mRows && v.GetSize() == mColumns, + "Invalid index in QForm\n"); + + return u.Dot((*this)*v); +} +//---------------------------------------------------------------------------- +template +GMatrix GMatrix::Transpose () const +{ + GMatrix result(mColumns, mRows); + for (int r = 0; r < mRows; ++r) + { + for (int c = 0; c < mColumns; ++c) + { + result.mEntry[c][r] = mEntry[r][c]; + } + } + return result; +} +//---------------------------------------------------------------------------- +template +GMatrix GMatrix::TransposeTimes (const GMatrix& mat) const +{ + // P = A^T*B, P[r][c] = sum_m A[m][r]*B[m][c] + assertion(mRows == mat.mRows, "Mismatch in TransposeTimes\n"); + + GMatrix result(mColumns, mat.mColumns); + for (int r = 0; r < result.mRows; ++r) + { + for (int c = 0; c < result.mColumns; ++c) + { + for (int m = 0; m < mRows; ++m) + { + result.mEntry[r][c] += mEntry[m][r] * mat.mEntry[m][c]; + } + } + } + return result; +} +//---------------------------------------------------------------------------- +template +GMatrix GMatrix::TimesTranspose (const GMatrix& mat) const +{ + // P = A*B^T, P[r][c] = sum_m A[r][m]*B[c][m] + assertion(mColumns == mat.mColumns, "Mismatch in TimesTranspose\n"); + + GMatrix result(mRows, mat.mRows); + for (int r = 0; r < result.mRows; ++r) + { + for (int c = 0; c < result.mColumns; ++c) + { + for (int m = 0; m < mColumns; ++m) + { + result.mEntry[r][c] += mEntry[r][m] * mat.mEntry[c][m]; + } + } + } + return result; +} +//---------------------------------------------------------------------------- +template +GMatrix GMatrix::TransposeTimesTranspose (const GMatrix& mat) + const +{ + // P = A*B^T, P[r][c] = sum_m A[m][r]*B[c][m] + assertion(mColumns == mat.mColumns, + "Mismatch in TransposeTimesTranspose\n"); + + GMatrix result(mColumns, mat.mRows); + for (int r = 0; r < result.mRows; ++r) + { + for (int c = 0; c < result.mColumns; ++c) + { + for (int m = 0; m < mColumns; ++m) + { + result.mEntry[r][c] += mEntry[m][r] * mat.mEntry[c][m]; + } + } + } + return result; +} +//---------------------------------------------------------------------------- +template +bool GMatrix::GetInverse (GMatrix& inverse) const +{ + // Computations are performed in-place. + if (GetRows() > 0 && GetRows() != GetColumns()) + { + return false; + } + + int size = GetRows(); + inverse = *this; + + int* colIndex = new1(size); + int* rowIndex = new1(size); + bool* pivoted = new1(size); + memset(pivoted, 0, size*sizeof(bool)); + + int i1, i2, row = 0, col = 0; + Real save; + + // Elimination by full pivoting. + for (int i0 = 0; i0 < size; ++i0) + { + // Search matrix (excluding pivoted rows) for maximum absolute entry. + Real max = (Real)0; + for (i1 = 0; i1 < size; ++i1) + { + if (!pivoted[i1]) + { + for (i2 = 0; i2 < size; ++i2) + { + if (!pivoted[i2]) + { + Real abs = Math::FAbs(inverse[i1][i2]); + if (abs > max) + { + max = abs; + row = i1; + col = i2; + } + } + } + } + } + + if (max == (Real)0) + { + // Matrix is not invertible. + delete1(colIndex); + delete1(rowIndex); + delete1(pivoted); + return false; + } + + pivoted[col] = true; + + // Swap rows so that A[col][col] contains the pivot entry. + if (row != col) + { + inverse.SwapRows(row, col); + } + + // Keep track of the permutations of the rows. + rowIndex[i0] = row; + colIndex[i0] = col; + + // Scale the row so that the pivot entry is 1. + Real inv = ((Real)1)/inverse[col][col]; + inverse[col][col] = (Real)1; + for (i2 = 0; i2 < size; ++i2) + { + inverse[col][i2] *= inv; + } + + // Zero out the pivot column locations in the other rows. + for (i1 = 0; i1 < size; ++i1) + { + if (i1 != col) + { + save = inverse[i1][col]; + inverse[i1][col] = (Real)0; + for (i2 = 0; i2 < size; ++i2) + { + inverse[i1][i2] -= inverse[col][i2]*save; + } + } + } + } + + // Reorder rows so that A[][] stores the inverse of the original matrix. + for (i1 = size-1; i1 >= 0; --i1) + { + if (rowIndex[i1] != colIndex[i1]) + { + for (i2 = 0; i2 < size; ++i2) + { + save = inverse[i2][rowIndex[i1]]; + inverse[i2][rowIndex[i1]] = inverse[i2][colIndex[i1]]; + inverse[i2][colIndex[i1]] = save; + } + } + } + + delete1(colIndex); + delete1(rowIndex); + delete1(pivoted); + return true; +} +//---------------------------------------------------------------------------- +template +void GMatrix::Allocate (bool setToZero) +{ + // assert: mRows, mColumns, and mQuantity already initialized + + mData = new1(mQuantity); + if (setToZero) + { + memset(mData, 0, mQuantity*sizeof(Real)); + } + + mEntry = new1(mRows); + for (int r = 0; r < mRows; ++r) + { + mEntry[r] = &mData[r*mColumns]; + } +} +//---------------------------------------------------------------------------- +template +void GMatrix::Deallocate () +{ + delete1(mData); + delete1(mEntry); +} +//---------------------------------------------------------------------------- + diff --git a/tjp/core/math/mean.hpp b/tjp/core/math/mean.hpp new file mode 100755 index 0000000..14ada1d --- /dev/null +++ b/tjp/core/math/mean.hpp @@ -0,0 +1,86 @@ +// +// Math.hpp +// amoeba +// +// Created by Timothy Prepscius on 12/30/16. +// Copyright © 2016 Timothy Prepscius. All rights reserved. +// + +#pragma once + +namespace tjp::core::math { + +template +struct Mean_SumDivide +{ + T t = zero(); + size_t count = 0; + + void add(const T &v) + { + t = t + v; + count++; + } + + T mean() const + { + return t / count; + } +}; + +// https://www.geeksforgeeks.org/program-for-average-of-an-array-without-running-into-overflow/ +template +struct Mean_AddDivide +{ + T t = zero(); + size_t count = 0; + + void add(const T &v) + { + ++count; + t = t + (v - t) / (count); + } + + T mean() const + { + return t / count; + } +} ; + +// https://www.geeksforgeeks.org/compute-average-two-numbers-without-overflow/ +template +struct Mean_AddDivideMod +{ + T t = zero(); + size_t count = 0; + + void add(const T &v) + { + ++count; + t = t + (v - t) / (count); + } + + T mean() const + { + return t / count; + } +} ; + +template +auto mean_(const U &u) +{ + T t; + for (auto &v: u) + t.add(v); + + return t.mean(); +} + +template +auto mean(const U &u) +{ + return mean_>(u); +} + +} // namespace +