├── .gitignore ├── LICENSE ├── README.md ├── src ├── LitMath.csproj ├── LitMath.sln ├── LitMath │ ├── Circle2.cs │ ├── Line2.cs │ ├── Matrix3.cs │ ├── Matrix4.cs │ ├── Quaternion.cs │ ├── Rectangle2.cs │ ├── Utils.cs │ ├── Vector2.cs │ ├── Vector3.cs │ └── ViewUtils.cs └── Properties │ └── AssemblyInfo.cs └── test ├── Program.cs ├── Properties └── AssemblyInfo.cs └── Test.csproj /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # MSTest test Results 33 | [Tt]est[Rr]esult*/ 34 | [Bb]uild[Ll]og.* 35 | 36 | # NUNIT 37 | *.VisualState.xml 38 | TestResult.xml 39 | 40 | # Build Results of an ATL Project 41 | [Dd]ebugPS/ 42 | [Rr]eleasePS/ 43 | dlldata.c 44 | 45 | # .NET Core 46 | project.lock.json 47 | project.fragment.lock.json 48 | artifacts/ 49 | **/Properties/launchSettings.json 50 | 51 | *_i.c 52 | *_p.c 53 | *_i.h 54 | *.ilk 55 | *.meta 56 | *.obj 57 | *.pch 58 | *.pdb 59 | *.pgc 60 | *.pgd 61 | *.rsp 62 | *.sbr 63 | *.tlb 64 | *.tli 65 | *.tlh 66 | *.tmp 67 | *.tmp_proj 68 | *.log 69 | *.vspscc 70 | *.vssscc 71 | .builds 72 | *.pidb 73 | *.svclog 74 | *.scc 75 | 76 | # Chutzpah Test files 77 | _Chutzpah* 78 | 79 | # Visual C++ cache files 80 | ipch/ 81 | *.aps 82 | *.ncb 83 | *.opendb 84 | *.opensdf 85 | *.sdf 86 | *.cachefile 87 | *.VC.db 88 | *.VC.VC.opendb 89 | 90 | # Visual Studio profiler 91 | *.psess 92 | *.vsp 93 | *.vspx 94 | *.sap 95 | 96 | # TFS 2012 Local Workspace 97 | $tf/ 98 | 99 | # Guidance Automation Toolkit 100 | *.gpState 101 | 102 | # ReSharper is a .NET coding add-in 103 | _ReSharper*/ 104 | *.[Rr]e[Ss]harper 105 | *.DotSettings.user 106 | 107 | # JustCode is a .NET coding add-in 108 | .JustCode 109 | 110 | # TeamCity is a build add-in 111 | _TeamCity* 112 | 113 | # DotCover is a Code Coverage Tool 114 | *.dotCover 115 | 116 | # Visual Studio code coverage results 117 | *.coverage 118 | *.coveragexml 119 | 120 | # NCrunch 121 | _NCrunch_* 122 | .*crunch*.local.xml 123 | nCrunchTemp_* 124 | 125 | # MightyMoose 126 | *.mm.* 127 | AutoTest.Net/ 128 | 129 | # Web workbench (sass) 130 | .sass-cache/ 131 | 132 | # Installshield output folder 133 | [Ee]xpress/ 134 | 135 | # DocProject is a documentation generator add-in 136 | DocProject/buildhelp/ 137 | DocProject/Help/*.HxT 138 | DocProject/Help/*.HxC 139 | DocProject/Help/*.hhc 140 | DocProject/Help/*.hhk 141 | DocProject/Help/*.hhp 142 | DocProject/Help/Html2 143 | DocProject/Help/html 144 | 145 | # Click-Once directory 146 | publish/ 147 | 148 | # Publish Web Output 149 | *.[Pp]ublish.xml 150 | *.azurePubxml 151 | # TODO: Comment the next line if you want to checkin your web deploy settings 152 | # but database connection strings (with potential passwords) will be unencrypted 153 | *.pubxml 154 | *.publishproj 155 | 156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 157 | # checkin your Azure Web App publish settings, but sensitive information contained 158 | # in these scripts will be unencrypted 159 | PublishScripts/ 160 | 161 | # NuGet Packages 162 | *.nupkg 163 | # The packages folder can be ignored because of Package Restore 164 | **/packages/* 165 | # except build/, which is used as an MSBuild target. 166 | !**/packages/build/ 167 | # Uncomment if necessary however generally it will be regenerated when needed 168 | #!**/packages/repositories.config 169 | # NuGet v3's project.json files produces more ignorable files 170 | *.nuget.props 171 | *.nuget.targets 172 | 173 | # Microsoft Azure Build Output 174 | csx/ 175 | *.build.csdef 176 | 177 | # Microsoft Azure Emulator 178 | ecf/ 179 | rcf/ 180 | 181 | # Windows Store app package directories and files 182 | AppPackages/ 183 | BundleArtifacts/ 184 | Package.StoreAssociation.xml 185 | _pkginfo.txt 186 | 187 | # Visual Studio cache files 188 | # files ending in .cache can be ignored 189 | *.[Cc]ache 190 | # but keep track of directories ending in .cache 191 | !*.[Cc]ache/ 192 | 193 | # Others 194 | ClientBin/ 195 | ~$* 196 | *~ 197 | *.dbmdl 198 | *.dbproj.schemaview 199 | *.jfm 200 | *.pfx 201 | *.publishsettings 202 | orleans.codegen.cs 203 | 204 | # Since there are multiple workflows, uncomment next line to ignore bower_components 205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 206 | #bower_components/ 207 | 208 | # RIA/Silverlight projects 209 | Generated_Code/ 210 | 211 | # Backup & report files from converting an old project file 212 | # to a newer Visual Studio version. Backup files are not needed, 213 | # because we have git ;-) 214 | _UpgradeReport_Files/ 215 | Backup*/ 216 | UpgradeLog*.XML 217 | UpgradeLog*.htm 218 | 219 | # SQL Server files 220 | *.mdf 221 | *.ldf 222 | *.ndf 223 | 224 | # Business Intelligence projects 225 | *.rdl.data 226 | *.bim.layout 227 | *.bim_*.settings 228 | 229 | # Microsoft Fakes 230 | FakesAssemblies/ 231 | 232 | # GhostDoc plugin setting file 233 | *.GhostDoc.xml 234 | 235 | # Node.js Tools for Visual Studio 236 | .ntvs_analysis.dat 237 | node_modules/ 238 | 239 | # Typescript v1 declaration files 240 | typings/ 241 | 242 | # Visual Studio 6 build log 243 | *.plg 244 | 245 | # Visual Studio 6 workspace options file 246 | *.opt 247 | 248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 249 | *.vbw 250 | 251 | # Visual Studio LightSwitch build output 252 | **/*.HTMLClient/GeneratedArtifacts 253 | **/*.DesktopClient/GeneratedArtifacts 254 | **/*.DesktopClient/ModelManifest.xml 255 | **/*.Server/GeneratedArtifacts 256 | **/*.Server/ModelManifest.xml 257 | _Pvt_Extensions 258 | 259 | # Paket dependency manager 260 | .paket/paket.exe 261 | paket-files/ 262 | 263 | # FAKE - F# Make 264 | .fake/ 265 | 266 | # JetBrains Rider 267 | .idea/ 268 | *.sln.iml 269 | 270 | # CodeRush 271 | .cr/ 272 | 273 | # Python Tools for Visual Studio (PTVS) 274 | __pycache__/ 275 | *.pyc 276 | 277 | # Cake - Uncomment if you are using it 278 | # tools/** 279 | # !tools/packages.config 280 | 281 | # Telerik's JustMock configuration file 282 | *.jmconfig 283 | 284 | # BizTalk build output 285 | *.btp.cs 286 | *.btm.cs 287 | *.odx.cs 288 | *.xsd.cs 289 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Hisin Wang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LitMath 2 | A simple 2D and 3D math library for C# 3 | # License 4 | MIT 5 | -------------------------------------------------------------------------------- /src/LitMath.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {5C1D6D42-A59E-4A42-84B0-F444E63736DF} 9 | Library 10 | Properties 11 | LitMath 12 | LitMath 13 | v2.0 14 | 512 15 | 16 | 17 | true 18 | full 19 | false 20 | ..\bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | ..\bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 59 | -------------------------------------------------------------------------------- /src/LitMath.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LitMath", "LitMath.csproj", "{5C1D6D42-A59E-4A42-84B0-F444E63736DF}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "..\test\Test.csproj", "{35D3E59A-F22F-4F75-8F65-C296EAFC7703}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Debug|Mixed Platforms = Debug|Mixed Platforms 12 | Debug|x86 = Debug|x86 13 | Release|Any CPU = Release|Any CPU 14 | Release|Mixed Platforms = Release|Mixed Platforms 15 | Release|x86 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {5C1D6D42-A59E-4A42-84B0-F444E63736DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {5C1D6D42-A59E-4A42-84B0-F444E63736DF}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {5C1D6D42-A59E-4A42-84B0-F444E63736DF}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU 21 | {5C1D6D42-A59E-4A42-84B0-F444E63736DF}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU 22 | {5C1D6D42-A59E-4A42-84B0-F444E63736DF}.Debug|x86.ActiveCfg = Debug|Any CPU 23 | {5C1D6D42-A59E-4A42-84B0-F444E63736DF}.Release|Any CPU.ActiveCfg = Release|Any CPU 24 | {5C1D6D42-A59E-4A42-84B0-F444E63736DF}.Release|Any CPU.Build.0 = Release|Any CPU 25 | {5C1D6D42-A59E-4A42-84B0-F444E63736DF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU 26 | {5C1D6D42-A59E-4A42-84B0-F444E63736DF}.Release|Mixed Platforms.Build.0 = Release|Any CPU 27 | {5C1D6D42-A59E-4A42-84B0-F444E63736DF}.Release|x86.ActiveCfg = Release|Any CPU 28 | {35D3E59A-F22F-4F75-8F65-C296EAFC7703}.Debug|Any CPU.ActiveCfg = Debug|x86 29 | {35D3E59A-F22F-4F75-8F65-C296EAFC7703}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 30 | {35D3E59A-F22F-4F75-8F65-C296EAFC7703}.Debug|Mixed Platforms.Build.0 = Debug|x86 31 | {35D3E59A-F22F-4F75-8F65-C296EAFC7703}.Debug|x86.ActiveCfg = Debug|x86 32 | {35D3E59A-F22F-4F75-8F65-C296EAFC7703}.Debug|x86.Build.0 = Debug|x86 33 | {35D3E59A-F22F-4F75-8F65-C296EAFC7703}.Release|Any CPU.ActiveCfg = Release|x86 34 | {35D3E59A-F22F-4F75-8F65-C296EAFC7703}.Release|Mixed Platforms.ActiveCfg = Release|x86 35 | {35D3E59A-F22F-4F75-8F65-C296EAFC7703}.Release|Mixed Platforms.Build.0 = Release|x86 36 | {35D3E59A-F22F-4F75-8F65-C296EAFC7703}.Release|x86.ActiveCfg = Release|x86 37 | {35D3E59A-F22F-4F75-8F65-C296EAFC7703}.Release|x86.Build.0 = Release|x86 38 | EndGlobalSection 39 | GlobalSection(SolutionProperties) = preSolution 40 | HideSolutionNode = FALSE 41 | EndGlobalSection 42 | EndGlobal 43 | -------------------------------------------------------------------------------- /src/LitMath/Circle2.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LitMath 4 | { 5 | public struct Circle2 6 | { 7 | public Vector2 center; 8 | public double radius; 9 | 10 | public double diameter 11 | { 12 | get { return radius * 2; } 13 | } 14 | 15 | public Circle2(Vector2 center, double radius) 16 | { 17 | this.center = center; 18 | this.radius = radius; 19 | } 20 | 21 | public override string ToString() 22 | { 23 | return string.Format("Circle2(({0}, {1}), {2})", 24 | this.center.x, this.center.y, this.radius); 25 | } 26 | 27 | /// 28 | /// 求通过3点的圆 29 | /// http://blog.csdn.net/liyuanbhu/article/details/52891868 30 | /// 31 | public static Circle2 From3Points(Vector2 pnt1, Vector2 pnt2, Vector2 pnt3) 32 | { 33 | Circle2 circle = new Circle2(); 34 | 35 | double a = pnt1.x - pnt2.x; 36 | double b = pnt1.y - pnt2.y; 37 | double c = pnt1.x - pnt3.x; 38 | double d = pnt1.y - pnt3.y; 39 | double e = (pnt1.x * pnt1.x - pnt2.x * pnt2.x + pnt1.y * pnt1.y - pnt2.y * pnt2.y) / 2.0; 40 | double f = (pnt1.x * pnt1.x - pnt3.x * pnt3.x + pnt1.y * pnt1.y - pnt3.y * pnt3.y) / 2.0; 41 | double det = b * c - a * d; 42 | 43 | if (Math.Abs(det) < Utils.EPSILON) 44 | { 45 | circle.center = new Vector2(0, 0); 46 | circle.radius = -1; 47 | } 48 | 49 | circle.center.x = -(d * e - b * f) / det; 50 | circle.center.y = -(a * f - c * e) / det; 51 | circle.radius = Math.Sqrt( 52 | (pnt1.x - circle.center.x) * (pnt1.x - circle.center.x) 53 | + (pnt1.y - circle.center.y) * (pnt1.y - circle.center.y)); 54 | 55 | return circle; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/LitMath/Line2.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LitMath 4 | { 5 | public struct Line2 6 | { 7 | public Vector2 startPoint; 8 | public Vector2 endPoint; 9 | 10 | public Line2(Vector2 startPnt, Vector2 endPnt) 11 | { 12 | this.startPoint = startPnt; 13 | this.endPoint = endPnt; 14 | } 15 | 16 | public Vector2 centerPoint 17 | { 18 | get 19 | { 20 | return new Vector2( 21 | (this.startPoint.x + this.endPoint.x) / 2.0, 22 | (this.startPoint.y + this.endPoint.y) / 2.0); 23 | } 24 | } 25 | 26 | public Vector2 direction 27 | { 28 | get 29 | { 30 | Vector2 vector = this.endPoint - this.startPoint; 31 | return vector.normalized; 32 | } 33 | } 34 | 35 | public double length 36 | { 37 | get 38 | { 39 | Vector2 vector = this.endPoint - this.startPoint; 40 | return vector.length; 41 | } 42 | } 43 | 44 | public override string ToString() 45 | { 46 | return string.Format( 47 | "Line2(({0}, {1}), ({2}, {3})", 48 | this.startPoint.x, 49 | this.startPoint.y, 50 | this.endPoint.x, 51 | this.endPoint.y); 52 | } 53 | 54 | /// 55 | /// 求线段的交点 56 | /// 57 | /// 线段1 58 | /// 线段2 59 | /// 交点 60 | /// 61 | /// true --- 相交 62 | /// false --- 不相交 63 | /// 64 | public static bool Intersect(Line2 line1st, Line2 line2nd, ref Vector2 intersection, 65 | double tolerance = 1e-10) 66 | { 67 | Vector2 p = line1st.startPoint; 68 | Vector2 r = line1st.endPoint - line1st.startPoint; 69 | Vector2 q = line2nd.startPoint; 70 | Vector2 s = line2nd.endPoint - line2nd.startPoint; 71 | double rxs = Vector2.Cross(r, s); 72 | if (!Utils.IsEqualZero(rxs, tolerance)) 73 | { 74 | double t = Vector2.Cross(q - p, s) / rxs; 75 | double u = Vector2.Cross(q - p, r) / rxs; 76 | if (t >= (0.0-tolerance) && t <= (1.0+tolerance) 77 | && u >= (0.0-tolerance) && u <= (1.0+tolerance)) 78 | { 79 | intersection = p + t * r; 80 | return true; 81 | } 82 | } 83 | return false; 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/LitMath/Matrix3.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LitMath 4 | { 5 | public struct Matrix3 6 | { 7 | public double m11; 8 | public double m12; 9 | public double m13; 10 | public double m21; 11 | public double m22; 12 | public double m23; 13 | public double m31; 14 | public double m32; 15 | public double m33; 16 | 17 | public Matrix3( 18 | double m11 = 0.0, double m12 = 0.0, double m13 = 0.0, 19 | double m21 = 0.0, double m22 = 0.0, double m23 = 0.0, 20 | double m31 = 0.0, double m32 = 0.0, double m33 = 0.0) 21 | { 22 | this.m11 = m11; 23 | this.m12 = m12; 24 | this.m13 = m13; 25 | this.m21 = m21; 26 | this.m22 = m22; 27 | this.m23 = m23; 28 | this.m31 = m31; 29 | this.m32 = m32; 30 | this.m33 = m33; 31 | } 32 | 33 | public void Set( 34 | double m11 = 0.0, double m12 = 0.0, double m13 = 0.0, 35 | double m21 = 0.0, double m22 = 0.0, double m23 = 0.0, 36 | double m31 = 0.0, double m32 = 0.0, double m33 = 0.0) 37 | { 38 | this.m11 = m11; 39 | this.m12 = m12; 40 | this.m13 = m13; 41 | this.m21 = m21; 42 | this.m22 = m22; 43 | this.m23 = m23; 44 | this.m31 = m31; 45 | this.m32 = m32; 46 | this.m33 = m33; 47 | } 48 | 49 | public override string ToString() 50 | { 51 | string pattern = @"Matrix3( 52 | {0,10:0.00}, {1,10:0.00}, {2,10:0.00}, 53 | {3,10:0.00}, {4,10:0.00}, {5,10:0.00}, 54 | {6,10:0.00}, {7,10:0.00}, {8,10:0.00} )"; 55 | return string.Format(pattern, 56 | m11, m12, m13, 57 | m21, m22, m23, 58 | m31, m32, m33); 59 | } 60 | 61 | public double determinant 62 | { 63 | get 64 | { 65 | return m11 * m22 * m33 + 66 | m12 * m23 * m31 + 67 | m13 * m21 * m32 - 68 | m11 * m23 * m32 - 69 | m12 * m21 * m33 - 70 | m13 * m22 * m31; 71 | } 72 | } 73 | 74 | public Matrix3 inverse 75 | { 76 | get 77 | { 78 | double d = this.determinant; 79 | if (d == 0.0) 80 | return Matrix3.identity; 81 | 82 | Matrix3 tmp = new Matrix3(); 83 | tmp.m11 = (m22 * m33 - m23 * m32) / d; 84 | tmp.m12 = (m13 * m32 - m12 * m33) / d; 85 | tmp.m13 = (m12 * m23 - m13 * m22) / d; 86 | tmp.m21 = (m23 * m31 - m21 * m33) / d; 87 | tmp.m22 = (m11 * m33 - m13 * m31) / d; 88 | tmp.m23 = (m13 * m21 - m11 * m23) / d; 89 | tmp.m31 = (m21 * m32 - m22 * m31) / d; 90 | tmp.m32 = (m12 * m31 - m11 * m32) / d; 91 | tmp.m33 = (m11 * m22 - m12 * m21) / d; 92 | return tmp; 93 | } 94 | } 95 | 96 | public Matrix3 transpose 97 | { 98 | get 99 | { 100 | return new Matrix3( 101 | m11, m21, m31, 102 | m12, m22, m32, 103 | m13, m23, m33); 104 | } 105 | } 106 | 107 | public Vector2 MultiplyPoint(Vector2 v) 108 | { 109 | return new Vector2( 110 | m11 * v.x + m12 * v.y + m13, 111 | m21 * v.x + m22 * v.y + m23); 112 | } 113 | 114 | public Vector2 MultiplyVector(Vector2 v) 115 | { 116 | return new Vector2( 117 | m11 * v.x + m12 * v.y, 118 | m21 * v.x + m22 * v.y); 119 | } 120 | 121 | public static Matrix3 identity 122 | { 123 | get 124 | { 125 | return new Matrix3( 126 | 1.0, 0.0, 0.0, 127 | 0.0, 1.0, 0.0, 128 | 0.0, 0.0, 1.0); 129 | } 130 | } 131 | 132 | public static Matrix3 zero 133 | { 134 | get 135 | { 136 | return new Matrix3( 137 | 0.0, 0.0, 0.0, 138 | 0.0, 0.0, 0.0, 139 | 0.0, 0.0, 0.0); 140 | } 141 | } 142 | 143 | public static Matrix3 Translate(Vector2 v) 144 | { 145 | return new Matrix3( 146 | 1.0, 0.0, v.x, 147 | 0.0, 1.0, v.y, 148 | 0.0, 0.0, 1.0); 149 | } 150 | 151 | public static Matrix3 Rotate(double angle) 152 | { 153 | return RotateInRadian(Utils.DegreeToRadian(angle)); 154 | } 155 | 156 | public static Matrix3 RotateInRadian(double angle) 157 | { 158 | double cos = Math.Cos(angle); 159 | double sin = Math.Sin(angle); 160 | return new Matrix3( 161 | cos, -sin, 0.0, 162 | sin, cos, 0.0, 163 | 0.0, 0.0, 1.0); 164 | } 165 | 166 | public static Matrix3 Scale(Vector2 v) 167 | { 168 | return new Matrix3( 169 | v.x, 0.0, 0.0, 170 | 0.0, v.y, 0.0, 171 | 0.0, 0.0, 1.0); 172 | } 173 | 174 | public static Matrix3 operator *(Matrix3 a, Matrix3 b) 175 | { 176 | Matrix3 M = new Matrix3(); 177 | M.m11 = a.m11 * b.m11 + a.m12 * b.m21 + a.m13 * b.m31; 178 | M.m12 = a.m11 * b.m12 + a.m12 * b.m22 + a.m13 * b.m32; 179 | M.m13 = a.m11 * b.m13 + a.m12 * b.m23 + a.m13 * b.m33; 180 | M.m21 = a.m21 * b.m11 + a.m22 * b.m21 + a.m23 * b.m31; 181 | M.m22 = a.m21 * b.m12 + a.m22 * b.m22 + a.m23 * b.m32; 182 | M.m23 = a.m21 * b.m13 + a.m22 * b.m23 + a.m23 * b.m33; 183 | M.m31 = a.m31 * b.m11 + a.m32 * b.m21 + a.m33 * b.m31; 184 | M.m32 = a.m31 * b.m12 + a.m32 * b.m22 + a.m33 * b.m32; 185 | M.m33 = a.m31 * b.m13 + a.m32 * b.m23 + a.m33 * b.m33; 186 | return M; 187 | } 188 | 189 | public static Vector2 operator *(Matrix3 m, Vector2 v) 190 | { 191 | return new Vector2( 192 | m.m11 * v.x + m.m12 * v.y + m.m13, 193 | m.m21 * v.x + m.m22 * v.y + m.m23); 194 | } 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /src/LitMath/Matrix4.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LitMath 4 | { 5 | public struct Matrix4 6 | { 7 | public double m11; 8 | public double m12; 9 | public double m13; 10 | public double m14; 11 | public double m21; 12 | public double m22; 13 | public double m23; 14 | public double m24; 15 | public double m31; 16 | public double m32; 17 | public double m33; 18 | public double m34; 19 | public double m41; 20 | public double m42; 21 | public double m43; 22 | public double m44; 23 | 24 | public Matrix4( 25 | double m11 = 0.0, double m12 = 0.0, double m13 = 0.0, double m14 = 0.0, 26 | double m21 = 0.0, double m22 = 0.0, double m23 = 0.0, double m24 = 0.0, 27 | double m31 = 0.0, double m32 = 0.0, double m33 = 0.0, double m34 = 0.0, 28 | double m41 = 0.0, double m42 = 0.0, double m43 = 0.0, double m44 = 0.0) 29 | { 30 | this.m11 = m11; 31 | this.m12 = m12; 32 | this.m13 = m13; 33 | this.m14 = m14; 34 | 35 | this.m21 = m21; 36 | this.m22 = m22; 37 | this.m23 = m23; 38 | this.m24 = m24; 39 | 40 | this.m31 = m31; 41 | this.m32 = m32; 42 | this.m33 = m33; 43 | this.m34 = m34; 44 | 45 | this.m41 = m41; 46 | this.m42 = m42; 47 | this.m43 = m43; 48 | this.m44 = m44; 49 | } 50 | 51 | public void Set( 52 | double m11 = 0.0, double m12 = 0.0, double m13 = 0.0, double m14 = 0.0, 53 | double m21 = 0.0, double m22 = 0.0, double m23 = 0.0, double m24 = 0.0, 54 | double m31 = 0.0, double m32 = 0.0, double m33 = 0.0, double m34 = 0.0, 55 | double m41 = 0.0, double m42 = 0.0, double m43 = 0.0, double m44 = 0.0) 56 | { 57 | this.m11 = m11; 58 | this.m12 = m12; 59 | this.m13 = m13; 60 | this.m14 = m14; 61 | 62 | this.m21 = m21; 63 | this.m22 = m22; 64 | this.m23 = m23; 65 | this.m24 = m24; 66 | 67 | this.m31 = m31; 68 | this.m32 = m32; 69 | this.m33 = m33; 70 | this.m34 = m34; 71 | 72 | this.m41 = m41; 73 | this.m42 = m42; 74 | this.m43 = m43; 75 | this.m44 = m44; 76 | } 77 | 78 | public override string ToString() 79 | { 80 | return string.Format(@"Matrix4( 81 | {0,10:0.00}, {1,10:0.00}, {2,10:0.00}, {3,10:0.00}, 82 | {4,10:0.00}, {5,10:0.00}, {6,10:0.00}, {7,10:0.00}, 83 | {8,10:0.00}, {9,10:0.00}, {10,10:0.00}, {11,10:0.00}, 84 | {12,10:0.00}, {13,10:0.00}, {14,10:0.00}, {15,10:0.00} )", 85 | m11, m12, m13, m14, 86 | m21, m22, m23, m24, 87 | m31, m32, m33, m34, 88 | m41, m42, m43, m44); 89 | } 90 | 91 | public double determinant 92 | { 93 | get 94 | { 95 | double A0 = m11 * m22 - m12 * m21; 96 | double A1 = m11 * m23 - m13 * m21; 97 | double A2 = m11 * m24 - m14 * m21; 98 | double A3 = m12 * m23 - m13 * m22; 99 | double A4 = m12 * m24 - m14 * m22; 100 | double A5 = m13 * m24 - m14 * m23; 101 | double B0 = m31 * m42 - m32 * m41; 102 | double B1 = m31 * m43 - m33 * m41; 103 | double B2 = m31 * m44 - m34 * m41; 104 | double B3 = m32 * m43 - m33 * m42; 105 | double B4 = m32 * m44 - m34 * m42; 106 | double B5 = m33 * m44 - m34 * m43; 107 | 108 | return A0*B5 - A1*B4 + A2*B3 + A3*B2 - A4*B1 + A5*B0; 109 | } 110 | } 111 | 112 | public Matrix4 inverse 113 | { 114 | get 115 | { 116 | double d = this.determinant; 117 | if (d == 0.0) 118 | return Matrix4.identity; 119 | 120 | Matrix4 M = new Matrix4(); 121 | M.m11 = (m23*m34*m42 - m24*m33*m42 + m24*m32*m43 - 122 | m22*m34*m43 - m23*m32*m44 + m22*m33*m44) / d; 123 | M.m12 = (m14*m33*m42 - m13*m34*m42 - m14*m32*m43 + 124 | m12*m34*m43 + m13*m32*m44 - m12*m33*m44) / d; 125 | M.m13 = (m13*m24*m42 - m14*m23*m42 + m14*m22*m43 - 126 | m12*m24*m43 - m13*m22*m44 + m12*m23*m44) / d; 127 | M.m14 = (m14*m23*m32 - m13*m24*m32 - m14*m22*m33 + 128 | m12*m24*m33 + m13*m22*m34 - m12*m23*m34) / d; 129 | M.m21 = (m24*m33*m41 - m23*m34*m41 - m24*m31*m43 + 130 | m21*m34*m43 + m23*m31*m44 - m21*m33*m44) / d; 131 | M.m22 = (m13*m34*m41 - m14*m33*m41 + m14*m31*m43 - 132 | m11*m34*m43 - m13*m31*m44 + m11*m33*m44) / d; 133 | M.m23 = (m14*m23*m41 - m13*m24*m41 - m14*m21*m43 + 134 | m11*m24*m43 + m13*m21*m44 - m11*m23*m44) / d; 135 | M.m24 = (m13*m24*m31 - m14*m23*m31 + m14*m21*m33 - 136 | m11*m24*m33 - m13*m21*m34 + m11*m23*m34) / d; 137 | M.m31 = (m22*m34*m41 - m24*m32*m41 + m24*m31*m42 - 138 | m21*m34*m42 - m22*m31*m44 + m21*m32*m44) / d; 139 | M.m32 = (m14*m32*m41 - m12*m34*m41 - m14*m31*m42 + 140 | m11*m34*m42 + m12*m31*m44 - m11*m32*m44) / d; 141 | M.m33 = (m12*m24*m41 - m14*m22*m41 + m14*m21*m42 - 142 | m11*m24*m42 - m12*m21*m44 + m11*m22*m44) / d; 143 | M.m34 = (m14*m22*m31 - m12*m24*m31 - m14*m21*m32 + 144 | m11*m24*m32 + m12*m21*m34 - m11*m22*m34) / d; 145 | M.m41 = (m23*m32*m41 - m22*m33*m41 - m23*m31*m42 + 146 | m21*m33*m42 + m22*m31*m43 - m21*m32*m43) / d; 147 | M.m42 = (m12*m33*m41 - m13*m32*m41 + m13*m31*m42 - 148 | m11*m33*m42 - m12*m31*m43 + m11*m32*m43) / d; 149 | M.m43 = (m13*m22*m41 - m12*m23*m41 - m13*m21*m42 + 150 | m11*m23*m42 + m12*m21*m43 - m11*m22*m43) / d; 151 | M.m44 = (m12*m23*m31 - m13*m22*m31 + m13*m21*m32 - 152 | m11*m23*m32 - m12*m21*m33 + m11*m22*m33) / d; 153 | return M; 154 | } 155 | } 156 | 157 | public Matrix4 transpose 158 | { 159 | get 160 | { 161 | return new Matrix4( 162 | m11, m21, m31, m41, 163 | m12, m22, m32, m42, 164 | m13, m23, m33, m43, 165 | m14, m24, m34, m44); 166 | } 167 | } 168 | 169 | public Vector3 MultiplyPoint(Vector3 v) 170 | { 171 | return new Vector3( 172 | m11 * v.x + m12 * v.y + m13 * v.z + m14, 173 | m21 * v.x + m22 * v.y + m23 * v.z + m24, 174 | m31 * v.x + m32 * v.y + m33 * v.z + m34); 175 | } 176 | 177 | public Vector3 MultiplyVector(Vector3 v) 178 | { 179 | return new Vector3( 180 | m11 * v.x + m12 * v.y + m13 * v.z, 181 | m21 * v.x + m22 * v.y + m23 * v.z, 182 | m31 * v.x + m32 * v.y + m33 * v.z); 183 | } 184 | 185 | public static Matrix4 identity 186 | { 187 | get 188 | { 189 | return new Matrix4( 190 | 1.0, 0.0, 0.0, 0.0, 191 | 0.0, 1.0, 0.0, 0.0, 192 | 0.0, 0.0, 1.0, 0.0, 193 | 0.0, 0.0, 0.0, 1.0); 194 | } 195 | } 196 | 197 | public static Matrix4 zero 198 | { 199 | get 200 | { 201 | return new Matrix4( 202 | 0.0, 0.0, 0.0, 0.0, 203 | 0.0, 0.0, 0.0, 0.0, 204 | 0.0, 0.0, 0.0, 0.0, 205 | 0.0, 0.0, 0.0, 0.0); 206 | } 207 | } 208 | 209 | public static Matrix4 Translate(Vector3 v) 210 | { 211 | return new Matrix4( 212 | 1.0, 0.0, 0.0, v.x, 213 | 0.0, 1.0, 0.0, v.y, 214 | 0.0, 0.0, 1.0, v.z, 215 | 0.0, 0.0, 0.0, 1.0); 216 | } 217 | 218 | public static Matrix4 RotateX(double angle) 219 | { 220 | return RotateXInRadian(Utils.DegreeToRadian(angle)); 221 | } 222 | 223 | public static Matrix4 RotateXInRadian(double angle) 224 | { 225 | double cos = Math.Cos(angle); 226 | double sin = Math.Sin(angle); 227 | return new Matrix4( 228 | 1.0, 0.0, 0.0, 0.0, 229 | 0.0, cos, -sin, 0.0, 230 | 0.0, sin, cos, 0.0, 231 | 0.0, 0.0, 0.0, 1.0); 232 | } 233 | 234 | public static Matrix4 RotateY(double angle) 235 | { 236 | return RotateYInRadian(Utils.DegreeToRadian(angle)); 237 | } 238 | 239 | public static Matrix4 RotateYInRadian(double angle) 240 | { 241 | double cos = Math.Cos(angle); 242 | double sin = Math.Sin(angle); 243 | return new Matrix4( 244 | cos, 0.0, sin, 0.0, 245 | 0.0, 1.0, 0.0, 0.0, 246 | -sin, 0.0, cos, 0.0, 247 | 0.0, 0.0, 0.0, 1.0); 248 | } 249 | 250 | public static Matrix4 RotateZ(double angle) 251 | { 252 | return RotateZInRadian(Utils.DegreeToRadian(angle)); 253 | } 254 | 255 | public static Matrix4 RotateZInRadian(double angle) 256 | { 257 | double cos = Math.Cos(angle); 258 | double sin = Math.Sin(angle); 259 | return new Matrix4( 260 | cos, -sin, 0.0, 0.0, 261 | sin, cos, 0.0, 0.0, 262 | 0.0, 0.0, 1.0, 0.0, 263 | 0.0, 0.0, 0.0, 1.0); 264 | } 265 | 266 | public static Matrix4 Scale(Vector3 v) 267 | { 268 | return new Matrix4( 269 | v.x, 0.0, 0.0, 0.0, 270 | 0.0, v.y, 0.0, 0.0, 271 | 0.0, 0.0, v.z, 0.0, 272 | 0.0, 0.0, 0.0, 1.0); 273 | } 274 | 275 | public static Matrix4 AngleAxis(double angle, Vector3 axis) 276 | { 277 | return AngleAxisInRadian(Utils.DegreeToRadian(angle), axis); 278 | } 279 | 280 | public static Matrix4 AngleAxisInRadian(double angle, Vector3 axis) 281 | { 282 | Vector3 n = axis.normalized; 283 | double x = n.x; 284 | double y = n.y; 285 | double z = n.z; 286 | double sin = Math.Sin(angle); 287 | double cos = Math.Cos(angle); 288 | double l_cos = 1.0 - cos; 289 | 290 | Matrix4 M = new Matrix4(); 291 | M.m11 = x * x * l_cos + cos; 292 | M.m12 = x * y * l_cos - z * sin; 293 | M.m13 = x * z * l_cos + y * sin; 294 | M.m21 = y * x * l_cos + z * sin; 295 | M.m22 = y * y * l_cos + cos; 296 | M.m23 = y * z * l_cos - x * sin; 297 | M.m31 = x * z * l_cos - y * sin; 298 | M.m32 = y * z * l_cos + x * sin; 299 | M.m33 = z * z * l_cos + cos; 300 | return M; 301 | } 302 | 303 | public static Matrix4 operator *(Matrix4 a, Matrix4 b) 304 | { 305 | Matrix4 M = new Matrix4(); 306 | 307 | M.m11 = a.m11 * b.m11 + a.m12 * b.m21 + a.m13 * b.m31 + a.m14 * b.m41; 308 | M.m12 = a.m11 * b.m12 + a.m12 * b.m22 + a.m13 * b.m32 + a.m14 * b.m42; 309 | M.m13 = a.m11 * b.m13 + a.m12 * b.m23 + a.m13 * b.m33 + a.m14 * b.m43; 310 | M.m14 = a.m11 * b.m14 + a.m12 * b.m24 + a.m13 * b.m34 + a.m14 * b.m44; 311 | 312 | M.m21 = a.m21 * b.m11 + a.m22 * b.m21 + a.m23 * b.m31 + a.m24 * b.m41; 313 | M.m22 = a.m21 * b.m12 + a.m22 * b.m22 + a.m23 * b.m32 + a.m24 * b.m42; 314 | M.m23 = a.m21 * b.m13 + a.m22 * b.m23 + a.m23 * b.m33 + a.m24 * b.m43; 315 | M.m24 = a.m21 * b.m14 + a.m22 * b.m24 + a.m23 * b.m34 + a.m24 * b.m44; 316 | 317 | M.m31 = a.m31 * b.m11 + a.m32 * b.m21 + a.m33 * b.m31 + a.m34 * b.m41; 318 | M.m32 = a.m31 * b.m12 + a.m32 * b.m22 + a.m33 * b.m32 + a.m34 * b.m42; 319 | M.m33 = a.m31 * b.m13 + a.m32 * b.m23 + a.m33 * b.m33 + a.m34 * b.m43; 320 | M.m34 = a.m31 * b.m14 + a.m32 * b.m24 + a.m33 * b.m34 + a.m34 * b.m44; 321 | 322 | M.m41 = a.m41 * b.m11 + a.m42 * b.m21 + a.m43 * b.m31 + a.m44 * b.m41; 323 | M.m42 = a.m41 * b.m12 + a.m42 * b.m22 + a.m43 * b.m32 + a.m44 * b.m42; 324 | M.m43 = a.m41 * b.m13 + a.m42 * b.m23 + a.m43 * b.m33 + a.m44 * b.m43; 325 | M.m44 = a.m41 * b.m14 + a.m42 * b.m24 + a.m43 * b.m34 + a.m44 * b.m44; 326 | 327 | return M; 328 | } 329 | 330 | public static Vector3 operator *(Matrix4 m, Vector3 v) 331 | { 332 | return new Vector3( 333 | m.m11 * v.x + m.m12 * v.y + m.m13 * v.z + m.m14, 334 | m.m21 * v.x + m.m22 * v.y + m.m23 * v.z + m.m24, 335 | m.m31 * v.x + m.m32 * v.y + m.m33 * v.z + m.m34); 336 | } 337 | } 338 | } 339 | -------------------------------------------------------------------------------- /src/LitMath/Quaternion.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LitMath 4 | { 5 | public struct Quaternion 6 | { 7 | public double x; 8 | public double y; 9 | public double z; 10 | public double w; 11 | 12 | public Quaternion(double x = 0.0, double y = 0.0, double z = 0.0, double w = 1.0) 13 | { 14 | this.x = x; 15 | this.y = y; 16 | this.z = z; 17 | this.w = w; 18 | } 19 | 20 | public void Set(double x, double y, double z, double w) 21 | { 22 | this.x = x; 23 | this.y = y; 24 | this.z = z; 25 | this.w = w; 26 | } 27 | 28 | public void SetIdentity() 29 | { 30 | Set(0.0, 0.0, 0.0, 1.0); 31 | } 32 | 33 | public override string ToString() 34 | { 35 | return string.Format("Quaternion({0}, {1}, {2}, {3})", 36 | x, y, z, w); 37 | } 38 | 39 | public double length 40 | { 41 | get 42 | { 43 | return Math.Sqrt(x*x + y*y + z*z + w*w); 44 | } 45 | } 46 | 47 | public void Normalize() 48 | { 49 | double len = this.length; 50 | if (len != 0.0) 51 | { 52 | this.x /= len; 53 | this.y /= len; 54 | this.z /= len; 55 | this.w /= len; 56 | } 57 | } 58 | 59 | public Quaternion normalized 60 | { 61 | get 62 | { 63 | double len = this.length; 64 | if (len != 0.0) 65 | { 66 | return new Quaternion(this.x / len, this.y / len, this.z / len, this.w / len); 67 | } 68 | return new Quaternion(this.x, this.y, this.z, this.w); 69 | } 70 | } 71 | 72 | public void Invert() 73 | { 74 | x = -x; 75 | y = -y; 76 | z = -z; 77 | } 78 | 79 | public Quaternion inverse 80 | { 81 | get 82 | { 83 | return new Quaternion(-x, -y, -z, w); 84 | } 85 | } 86 | 87 | public Matrix4 ToMatrix4() 88 | { 89 | Matrix4 matrix = new Matrix4(); 90 | matrix.m11 = 1.0-2.0*(y*y+z*z); 91 | matrix.m12 = 2.0*(x*y-z*w); 92 | matrix.m13 = 2.0*(x*z+y*w); 93 | matrix.m14 = 0.0; 94 | 95 | matrix.m21 = 2.0*(x*y+z*w); 96 | matrix.m22 = 1.0-2.0*(x*x+z*z); 97 | matrix.m23 = 2.0*(y*z-x*w); 98 | matrix.m24 = 0.0; 99 | 100 | matrix.m31 = 2.0*(x*z-y*w); 101 | matrix.m32 = 2.0*(y*z+x*w); 102 | matrix.m33 = 1.0-2.0*(x*x+y*y); 103 | matrix.m34 = 0.0; 104 | 105 | matrix.m41 = 0.0; 106 | matrix.m42 = 0.0; 107 | matrix.m43 = 0.0; 108 | matrix.m44 = 1.0; 109 | 110 | return matrix; 111 | } 112 | 113 | public static Quaternion identity 114 | { 115 | get 116 | { 117 | return new Quaternion(0.0, 0.0, 0.0, 1.0); 118 | } 119 | } 120 | 121 | public static Quaternion AngleAxis(double angle, Vector3 axis) 122 | { 123 | return AngleAxisInRadian(Utils.DegreeToRadian(angle), axis); 124 | } 125 | 126 | public static Quaternion AngleAxisInRadian(double angle, Vector3 axis) 127 | { 128 | axis = axis.normalized; 129 | double scale = Math.Sin(angle / 2); 130 | 131 | Quaternion quat = new Quaternion(); 132 | quat.w = Math.Cos(angle / 2); 133 | quat.x = axis.x * scale; 134 | quat.y = axis.y * scale; 135 | quat.z = axis.z * scale; 136 | 137 | return quat; 138 | } 139 | 140 | public static Quaternion FromToRotation(Vector3 from, Vector3 to) 141 | { 142 | Vector3 u = from.normalized; 143 | Vector3 v = to.normalized; 144 | double dot = Vector3.Dot(u, v); 145 | Vector3 w = Vector3.Cross(u, v); 146 | 147 | if (w.length == 0.0) 148 | { 149 | if (dot >= 0.0) 150 | { 151 | return Quaternion.identity; 152 | } 153 | else 154 | { 155 | Vector3 t = Vector3.Cross(u, new Vector3(1.0, 0.0, 0.0)); 156 | if (Utils.IsEqualZero(t.length)) 157 | { 158 | t = Vector3.Cross(u, new Vector3(0.0, 1.0, 0.0)); 159 | } 160 | return new Quaternion(t.x, t.y, t.z, 0.0); 161 | } 162 | } 163 | else 164 | { 165 | double angleInRad = Math.Acos(dot); 166 | return Quaternion.AngleAxisInRadian(angleInRad, w); 167 | } 168 | } 169 | 170 | public static Quaternion operator *(Quaternion a, Quaternion b) 171 | { 172 | return new Quaternion( 173 | a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y, 174 | a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x, 175 | a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w, 176 | a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z); 177 | } 178 | 179 | public static Vector3 operator *(Quaternion q, Vector3 v) 180 | { 181 | double x = q.x; 182 | double y = q.y; 183 | double z = q.z; 184 | double w = q.w; 185 | double x2 = q.x * q.x; 186 | double y2 = q.y * q.y; 187 | double z2 = q.z * q.z; 188 | double w2 = q.w * q.w; 189 | 190 | return new Vector3( 191 | (x2 + w2 - y2 - z2) * v.x + 2.0 * (x * y - z * w) * v.y + 2.0 * (x * z + y * w) * v.z, 192 | 2.0 * (x * y + z * w) * v.x + (w2 - x2 + y2 - z2) * v.y + 2.0 * (y * z - x * w) * v.z, 193 | 2.0 * (x * z - y * w) * v.x + 2.0 * (x * w + y * z) * v.y + (w2 - x2 - y2 + z2) * v.z); 194 | } 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /src/LitMath/Rectangle2.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LitMath 4 | { 5 | public struct Rectangle2 6 | { 7 | /// 8 | /// 位置,也就是矩形的左下角坐标 9 | /// 10 | public Vector2 location; 11 | 12 | /// 13 | /// 宽、高 14 | /// 15 | public double width; 16 | public double height; 17 | 18 | public Vector2 leftBottom 19 | { 20 | get { return location; } 21 | } 22 | 23 | public Vector2 leftTop 24 | { 25 | get 26 | { 27 | return new Vector2(this.location.x, this.location.y + height); 28 | } 29 | } 30 | 31 | public Vector2 rightTop 32 | { 33 | get 34 | { 35 | return new Vector2(this.location.x + this.width, 36 | this.location.y + this.height); 37 | } 38 | } 39 | 40 | public Vector2 rightBottom 41 | { 42 | get 43 | { 44 | return new Vector2(this.location.x + this.width, this.location.y); 45 | } 46 | } 47 | 48 | public Rectangle2(Vector2 location, double width, double height) 49 | { 50 | this.location = location; 51 | this.width = width; 52 | this.height = height; 53 | } 54 | 55 | public Rectangle2(Vector2 point1, Vector2 point2) 56 | { 57 | double minX = point1.x < point2.x ? point1.x : point2.x; 58 | double minY = point1.y < point2.y ? point1.y : point2.y; 59 | this.location = new Vector2(minX, minY); 60 | this.width = Math.Abs(point2.x - point1.x); 61 | this.height = Math.Abs(point2.y - point1.y); 62 | } 63 | 64 | public override string ToString() 65 | { 66 | return string.Format("Rectangle2(({0}, {1}), {2}, {3})", 67 | this.location.x, 68 | this.location.y, 69 | this.width, 70 | this.height); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/LitMath/Utils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace LitMath 6 | { 7 | public class Utils 8 | { 9 | public const double EPSILON = 1E-05; 10 | public const double PI = 3.14159265358979323846; 11 | 12 | public static double Clamp(double value, double minv, double maxv) 13 | { 14 | return Math.Max(Math.Min(value, maxv), minv); 15 | } 16 | 17 | public static double DegreeToRadian(double angle) 18 | { 19 | return ((angle * PI) / 180.0); 20 | } 21 | 22 | public static bool IsEqual(double x, double y, double epsilon = EPSILON) 23 | { 24 | return IsEqualZero(x - y, epsilon); 25 | } 26 | 27 | public static bool IsEqualZero(double x, double epsilon = EPSILON) 28 | { 29 | return (Math.Abs(x) < epsilon); 30 | } 31 | 32 | public static double RadianToDegree(double angle) 33 | { 34 | return ((angle * 180.0) / PI); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/LitMath/Vector2.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LitMath 4 | { 5 | public struct Vector2 6 | { 7 | public double x; 8 | public double y; 9 | 10 | public Vector2(double x = 0.0, double y = 0.0) 11 | { 12 | this.x = x; 13 | this.y = y; 14 | } 15 | 16 | public void Set(double newX, double newY) 17 | { 18 | this.x = newX; 19 | this.y = newY; 20 | } 21 | 22 | public override string ToString() 23 | { 24 | return string.Format("Vector2({0}, {1})", this.x, this.y); 25 | } 26 | 27 | public override bool Equals(object obj) 28 | { 29 | if (!(obj is Vector2)) 30 | return false; 31 | 32 | return Equals((Vector2)obj); 33 | } 34 | 35 | public bool Equals(Vector2 rhs) 36 | { 37 | return (Utils.IsEqual(x, rhs.x) && Utils.IsEqual(y, rhs.y)); 38 | } 39 | 40 | public override int GetHashCode() 41 | { 42 | return x.GetHashCode() ^ y.GetHashCode(); 43 | } 44 | 45 | public double length 46 | { 47 | get 48 | { 49 | return Math.Sqrt((this.x * this.x) + (this.y * this.y)); 50 | } 51 | } 52 | 53 | public double lengthSqrd 54 | { 55 | get 56 | { 57 | return ((this.x * this.x) + (this.y * this.y)); 58 | } 59 | } 60 | 61 | public void Normalize() 62 | { 63 | double length = this.length; 64 | if (length != 0.0) 65 | { 66 | this.x /= length; 67 | this.y /= length; 68 | } 69 | } 70 | 71 | public Vector2 normalized 72 | { 73 | get 74 | { 75 | double length = this.length; 76 | if (length != 0.0) 77 | { 78 | return new Vector2(this.x / length, this.y / length); 79 | } 80 | return this; 81 | } 82 | } 83 | 84 | public static double Dot(Vector2 a, Vector2 b) 85 | { 86 | return a.x * b.x + a.y * b.y; 87 | } 88 | 89 | public static double Cross(Vector2 a, Vector2 b) 90 | { 91 | return ((a.x * b.y) - (a.y * b.x)); 92 | } 93 | 94 | /// 95 | /// Returns the unsigned angle in degrees between a and b. 96 | /// The smaller of the two possible angles between the two vectors is used. 97 | /// The result value range: [0, 180] 98 | /// 99 | public static double Angle(Vector2 a, Vector2 b) 100 | { 101 | return Utils.RadianToDegree(AngleInRadian(a, b)); 102 | } 103 | 104 | /// 105 | /// Returns the unsigned angle in radians between a and b. 106 | /// The smaller of the two possible angles between the two vectors is used. 107 | /// The result value range: [0, PI] 108 | /// 109 | public static double AngleInRadian(Vector2 a, Vector2 b) 110 | { 111 | double num = a.length * b.length; 112 | if (num == 0.0) 113 | { 114 | return 0.0; 115 | } 116 | double num2 = Dot(a, b) / num; 117 | return Math.Acos(Utils.Clamp(num2, -1.0, 1.0)); 118 | } 119 | 120 | /// 121 | /// Returns the signed acute clockwise angle in degrees between from and to. 122 | /// The result value range: [-180, 180] 123 | /// 124 | public static double SignedAngle(Vector2 from, Vector2 to) 125 | { 126 | return Utils.RadianToDegree(SignedAngleInRadian(from, to)); 127 | } 128 | 129 | /// 130 | /// Returns the signed acute clockwise angle in radians between from and to. 131 | /// The result value range: [-PI, PI] 132 | /// 133 | public static double SignedAngleInRadian(Vector2 from, Vector2 to) 134 | { 135 | double rad = AngleInRadian(from, to); 136 | if (Cross(from, to) < 0) 137 | { 138 | rad = -rad; 139 | } 140 | return rad; 141 | } 142 | 143 | public static double Distance(Vector2 a, Vector2 b) 144 | { 145 | Vector2 vector = b - a; 146 | return vector.length; 147 | } 148 | 149 | public static Vector2 Rotate(Vector2 v, double angle) 150 | { 151 | return RotateInRadian(v, Utils.DegreeToRadian(angle)); 152 | } 153 | 154 | public static Vector2 Rotate(Vector2 point, Vector2 basePoint, double angle) 155 | { 156 | return RotateInRadian(point, basePoint, Utils.DegreeToRadian(angle)); 157 | } 158 | 159 | public static Vector2 RotateInRadian(Vector2 v, double rad) 160 | { 161 | double x = v.x * Math.Cos(rad) - v.y * Math.Sin(rad); 162 | double y = v.x * Math.Sin(rad) + v.y * Math.Cos(rad); 163 | return new Vector2(x, y); 164 | } 165 | 166 | public static Vector2 RotateInRadian(Vector2 point, Vector2 basePoint, double rad) 167 | { 168 | double cos = Math.Cos(rad); 169 | double sin = Math.Sin(rad); 170 | double x = point.x * cos - point.y * sin + basePoint.x * (1 - cos) + basePoint.y * sin; 171 | double y = point.x * sin + point.y * cos + basePoint.y * (1 - cos) + basePoint.x * sin; 172 | 173 | return new Vector2(x, y); 174 | } 175 | 176 | public static Vector2 operator +(Vector2 a, Vector2 b) 177 | { 178 | return new Vector2(a.x + b.x, a.y + b.y); 179 | } 180 | 181 | public static Vector2 operator -(Vector2 a, Vector2 b) 182 | { 183 | return new Vector2(a.x - b.x, a.y - b.y); 184 | } 185 | 186 | public static Vector2 operator -(Vector2 a) 187 | { 188 | return new Vector2(-a.x, -a.y); 189 | } 190 | 191 | public static Vector2 operator *(Vector2 a, double d) 192 | { 193 | return new Vector2(a.x * d, a.y * d); 194 | } 195 | 196 | public static Vector2 operator *(double d, Vector2 a) 197 | { 198 | return new Vector2(a.x * d, a.y * d); 199 | } 200 | 201 | public static Vector2 operator /(Vector2 a, double d) 202 | { 203 | return new Vector2(a.x / d, a.y / d); 204 | } 205 | 206 | public static bool operator ==(Vector2 lhs, Vector2 rhs) 207 | { 208 | return lhs.Equals(rhs); 209 | } 210 | 211 | public static bool operator !=(Vector2 lhs, Vector2 rhs) 212 | { 213 | return !(lhs == rhs); 214 | } 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /src/LitMath/Vector3.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LitMath 4 | { 5 | public struct Vector3 6 | { 7 | public double x; 8 | public double y; 9 | public double z; 10 | 11 | public Vector3(double x = 0.0, double y = 0.0, double z = 0.0) 12 | { 13 | this.x = x; 14 | this.y = y; 15 | this.z = z; 16 | } 17 | 18 | public void Set(double newX, double newY, double newZ) 19 | { 20 | this.x = newX; 21 | this.y = newY; 22 | this.z = newZ; 23 | } 24 | 25 | public override string ToString() 26 | { 27 | return string.Format("Vector3({0}, {1}, {2})", this.x, this.y, this.z); 28 | } 29 | 30 | public override bool Equals(object obj) 31 | { 32 | if (!(obj is Vector3)) 33 | return false; 34 | 35 | return Equals((Vector3)obj); 36 | } 37 | 38 | public bool Equals(Vector3 rhs) 39 | { 40 | return Utils.IsEqual(x, rhs.x) 41 | && Utils.IsEqual(y, rhs.y) 42 | && Utils.IsEqual(z, rhs.z); 43 | } 44 | 45 | public override int GetHashCode() 46 | { 47 | return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode(); 48 | } 49 | 50 | public double length 51 | { 52 | get 53 | { 54 | return Math.Sqrt(((this.x * this.x) + (this.y * this.y)) + (this.z * this.z)); 55 | } 56 | } 57 | 58 | public double lengthSqrd 59 | { 60 | get 61 | { 62 | return (((this.x * this.x) + (this.y * this.y)) + (this.z * this.z)); 63 | } 64 | } 65 | 66 | public void Normalize() 67 | { 68 | double length = this.length; 69 | if (length != 0.0) 70 | { 71 | this.x /= length; 72 | this.y /= length; 73 | this.z /= length; 74 | } 75 | } 76 | 77 | public Vector3 normalized 78 | { 79 | get 80 | { 81 | double length = this.length; 82 | if (length != 0.0) 83 | { 84 | return new Vector3(this.x / length, this.y / length, this.z / length); 85 | } 86 | return this; 87 | } 88 | } 89 | 90 | public static double Dot(Vector3 a, Vector3 b) 91 | { 92 | return a.x * b.x + a.y * b.y + a.z * b.z; 93 | } 94 | 95 | public static Vector3 Cross(Vector3 a, Vector3 b) 96 | { 97 | return new Vector3( 98 | (a.y * b.z) - (a.z * b.y), 99 | (a.z * b.x) - (a.x * b.z), 100 | (a.x * b.y) - (a.y * b.x)); 101 | } 102 | 103 | /// 104 | /// Returns the unsigned angle in degrees between a and b. 105 | /// The smaller of the two possible angles between the two vectors is used. 106 | /// The result value range: [0, 180] 107 | /// 108 | public static double Angle(Vector3 a, Vector3 b) 109 | { 110 | return Utils.RadianToDegree(AngleInRadian(a, b)); 111 | } 112 | 113 | /// 114 | /// Returns the unsigned angle in radians between a and b. 115 | /// The smaller of the two possible angles between the two vectors is used. 116 | /// The result value range: [0, PI] 117 | /// 118 | public static double AngleInRadian(Vector3 a, Vector3 b) 119 | { 120 | double num = a.length * b.length; 121 | if (num == 0.0) 122 | { 123 | return 0.0; 124 | } 125 | double num2 = Dot(a, b) / num; 126 | return Math.Acos(Utils.Clamp(num2, -1.0, 1.0)); 127 | } 128 | 129 | /// 130 | /// Returns the signed acute clockwise angle in degrees between from and to. 131 | /// The result value range: [-180, 180] 132 | /// The vector from which the angular difference is measured. 133 | /// The vector to which the angular difference is measured. 134 | /// A vector around which the other vectors are rotated. 135 | /// 136 | public static double SignedAngle(Vector3 from, Vector3 to, Vector3 axis) 137 | { 138 | return Utils.RadianToDegree(SignedAngleInRadian(from, to, axis)); 139 | } 140 | 141 | /// 142 | /// Returns the signed acute clockwise angle in radians between from and to. 143 | /// The result value range: [-PI, PI] 144 | /// The vector from which the angular difference is measured. 145 | /// The vector to which the angular difference is measured. 146 | /// A vector around which the other vectors are rotated. 147 | /// 148 | public static double SignedAngleInRadian(Vector3 from, Vector3 to, Vector3 axis) 149 | { 150 | double rad = AngleInRadian(from, to); 151 | Vector3 n = Cross(from, to); 152 | if (Dot(n, axis) < 0) 153 | { 154 | rad = -rad; 155 | } 156 | 157 | return rad; 158 | } 159 | 160 | public static double Distance(Vector3 a, Vector3 b) 161 | { 162 | return (b - a).length; 163 | } 164 | 165 | public static Vector3 operator +(Vector3 a, Vector3 b) 166 | { 167 | return new Vector3(a.x + b.x, a.y + b.y, a.z + b.z); 168 | } 169 | 170 | public static Vector3 operator -(Vector3 a, Vector3 b) 171 | { 172 | return new Vector3(a.x - b.x, a.y - b.y, a.z - b.z); 173 | } 174 | 175 | public static Vector3 operator -(Vector3 v) 176 | { 177 | return new Vector3(-v.x, -v.y, -v.z); 178 | } 179 | 180 | public static Vector3 operator *(Vector3 v, double d) 181 | { 182 | return new Vector3(v.x * d, v.y * d, v.z * d); 183 | } 184 | 185 | public static Vector3 operator *(double d, Vector3 v) 186 | { 187 | return new Vector3(v.x * d, v.y * d, v.z * d); 188 | } 189 | 190 | public static Vector3 operator /(Vector3 v, double d) 191 | { 192 | return new Vector3(v.x / d, v.y / d, v.z / d); 193 | } 194 | 195 | public static bool operator ==(Vector3 lhs, Vector3 rhs) 196 | { 197 | return lhs.Equals(rhs); 198 | } 199 | 200 | public static bool operator !=(Vector3 lhs, Vector3 rhs) 201 | { 202 | return !(lhs == rhs); 203 | } 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /src/LitMath/ViewUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace LitMath 6 | { 7 | public class ViewUtils 8 | { 9 | public static Matrix4 ViewMatrix(Vector3 pos, Vector3 xAxis, Vector3 yAxis) 10 | { 11 | Vector3 xDir = xAxis.normalized; 12 | Vector3 yDir = yAxis.normalized; 13 | Vector3 zDir = Vector3.Cross(xDir, yDir).normalized; 14 | 15 | Matrix4 mRot = new Matrix4( 16 | xDir.x, xDir.y, xDir.z, 0, 17 | yDir.x, yDir.y, yDir.z, 0, 18 | zDir.x, zDir.y, zDir.z, 0, 19 | 0, 0, 0, 1); 20 | 21 | Matrix4 mPos = new Matrix4( 22 | 1, 0, 0, -pos.x, 23 | 0, 1, 0, -pos.y, 24 | 0, 0, 1, -pos.z, 25 | 0, 0, 0, 1); 26 | 27 | return mRot * mPos; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的常规信息通过以下 6 | // 特性集控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("LitMath")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("LitMath")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 将 ComVisible 设置为 false 使此程序集中的类型 18 | // 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型, 19 | // 则将该类型上的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("ff1a9432-4167-4ab1-850a-14e12ff34559")] 24 | 25 | // 程序集的版本信息由下面四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 内部版本号 30 | // 修订号 31 | // 32 | // 可以指定所有这些值,也可以使用“内部版本号”和“修订号”的默认值, 33 | // 方法是按如下所示使用“*”: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("0.0.1.1")] 36 | [assembly: AssemblyFileVersion("0.0.1.1")] 37 | -------------------------------------------------------------------------------- /test/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Test 6 | { 7 | class Program 8 | { 9 | static void Main(string[] args) 10 | { 11 | //LitMath.Vector2 v = new LitMath.Vector2(0.7, 0.7); 12 | //v = LitMath.Vector2.RotateInRadian(v, LitMath.Utils.PI / 2); 13 | //Console.WriteLine(v.ToString()); 14 | //Console.WriteLine(Math.Asin(0.5).ToString()); 15 | 16 | { 17 | LitMath.Vector3 va = new LitMath.Vector3(0, 0, 1); 18 | LitMath.Vector3 vb = new LitMath.Vector3(0, 1, 0); 19 | LitMath.Vector3 axis = new LitMath.Vector3(1, 1, 0); 20 | double angle = LitMath.Vector3.SignedAngle(va, vb, axis); 21 | Console.WriteLine(angle); 22 | } 23 | { 24 | LitMath.Vector3 va = new LitMath.Vector3(0, 0, 1); 25 | LitMath.Vector3 vb = new LitMath.Vector3(0, 0, 1); 26 | LitMath.Vector3 axis = new LitMath.Vector3(1, 1, 0); 27 | double angle = LitMath.Vector3.SignedAngle(va, vb, axis); 28 | Console.WriteLine(angle); 29 | } 30 | { 31 | LitMath.Vector3 va = new LitMath.Vector3(0, 0, 1); 32 | LitMath.Vector3 vb = new LitMath.Vector3(0, 1, 0); 33 | LitMath.Vector3 axis = new LitMath.Vector3(0, 1, 1); 34 | double angle = LitMath.Vector3.SignedAngle(va, vb, axis); 35 | Console.WriteLine(angle); 36 | } 37 | 38 | 39 | return; 40 | //LitMath.Vector2 v1 = new LitMath.Vector2(1, 3); 41 | //Console.WriteLine(v1.ToString()); 42 | 43 | LitMath.Line2 line1 = new LitMath.Line2( 44 | new LitMath.Vector2(0, 0), 45 | new LitMath.Vector2(10, 0)); 46 | line1.startPoint.x = 10; 47 | LitMath.Line2 line2 = new LitMath.Line2( 48 | new LitMath.Vector2(5, 0), 49 | new LitMath.Vector2(5, 10)); 50 | 51 | LitMath.Vector2 intersection = new LitMath.Vector2(); 52 | if (LitMath.Line2.Intersect(line1, line2, ref intersection)) 53 | { 54 | Console.WriteLine("相交: " + intersection.ToString()); 55 | } 56 | 57 | LitMath.Rectangle2 rect = new LitMath.Rectangle2(new LitMath.Vector2(10, 10), 10, 20); 58 | Console.WriteLine(rect.ToString()); 59 | Console.WriteLine(rect.leftBottom.ToString()); 60 | Console.WriteLine(rect.leftTop.ToString()); 61 | Console.WriteLine(rect.rightTop.ToString()); 62 | Console.WriteLine(rect.rightBottom.ToString()); 63 | 64 | LitMath.Circle2 circle = new LitMath.Circle2(new LitMath.Vector2(25, 25), 10); 65 | Console.WriteLine(circle.ToString()); 66 | Console.WriteLine(circle.diameter.ToString()); 67 | } 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /test/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的常规信息通过以下 6 | // 特性集控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("Test")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Test")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 将 ComVisible 设置为 false 使此程序集中的类型 18 | // 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型, 19 | // 则将该类型上的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("779bbc10-9570-425a-8cd6-68fc70316fc4")] 24 | 25 | // 程序集的版本信息由下面四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 内部版本号 30 | // 修订号 31 | // 32 | // 可以指定所有这些值,也可以使用“内部版本号”和“修订号”的默认值, 33 | // 方法是按如下所示使用“*”: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /test/Test.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | x86 6 | 8.0.30703 7 | 2.0 8 | {35D3E59A-F22F-4F75-8F65-C296EAFC7703} 9 | Exe 10 | Properties 11 | Test 12 | Test 13 | v2.0 14 | 512 15 | 16 | 17 | x86 18 | true 19 | full 20 | false 21 | ..\bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | x86 28 | pdbonly 29 | true 30 | ..\bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | {5C1D6D42-A59E-4A42-84B0-F444E63736DF} 47 | LitMath 48 | 49 | 50 | 51 | 58 | --------------------------------------------------------------------------------