├── .gitignore
├── LICENSE
├── README.md
├── TcMatrix.sln
├── TcMatrix
├── LibraryCategory.libcat.xml
├── TcMatrix.tspproj
├── TcMatrix.tspproj.bak
└── TcMatrix
│ ├── POUs
│ ├── Array2DStaticMatrix.TcPOU
│ ├── Csv
│ │ ├── MatrixCsvReader.TcPOU
│ │ └── MatrixCsvWriter.TcPOU
│ ├── DynamicMatrix.TcPOU
│ ├── ExternalStaticMatrix.TcPOU
│ ├── Functions
│ │ ├── Arrays
│ │ │ ├── Array2D_Cols.TcPOU
│ │ │ ├── Array2D_Rows.TcPOU
│ │ │ ├── Array2D_To_Matrix.TcPOU
│ │ │ ├── Matrix_SameSizeAs_Array2D.TcPOU
│ │ │ └── Matrix_To_Array2D.TcPOU
│ │ ├── Matrix
│ │ │ ├── Matrix_CanMult.TcPOU
│ │ │ ├── Matrix_Copy.TcPOU
│ │ │ ├── Matrix_DeterminateSquare.TcPOU
│ │ │ ├── Matrix_ElementDifference.TcPOU
│ │ │ ├── Matrix_ElementProduct.TcPOU
│ │ │ ├── Matrix_ElementSum.TcPOU
│ │ │ ├── Matrix_Grow.TcPOU
│ │ │ ├── Matrix_InvertSquare.TcPOU
│ │ │ ├── Matrix_Product.TcPOU
│ │ │ ├── Matrix_Scale.TcPOU
│ │ │ ├── Matrix_Shrink.TcPOU
│ │ │ ├── Matrix_SubMatrix.TcPOU
│ │ │ ├── Matrix_Transpose.TcPOU
│ │ │ └── Matrix_TransposeSquare.TcPOU
│ │ └── Vector
│ │ │ ├── Vector_CrossProduct.TcPOU
│ │ │ ├── Vector_DotProduct.TcPOU
│ │ │ ├── Vector_Magnitude.TcPOU
│ │ │ └── Vector_Normalize.TcPOU
│ ├── Matrix.TcPOU
│ ├── MatrixAccessors
│ │ ├── MatrixAccessor.TcPOU
│ │ ├── ShrunkMatrixAccessor.TcPOU
│ │ ├── SubMatrixAccessor.TcPOU
│ │ └── TransposeMatrixAccessor.TcPOU
│ └── StaticMatrix.TcPOU
│ ├── TcMatrix.plcproj
│ └── Version
│ └── Global_Version.TcGVL
└── TcMatrixTest
├── TcMatrixTest.tsproj
└── TcMatrixTest
├── PlcTask.TcTTO
├── TESTs
├── FB_Array_Test.TcPOU
├── FB_CsvReadWrite_Test.TcPOU
├── FB_DynamicMatrix_Test.TcPOU
├── FB_MatrixDeterminate_Test.TcPOU
├── FB_MatrixElementProduct_Test.TcPOU
├── FB_MatrixElementSum_Test.TcPOU
├── FB_MatrixGetMagicSquare_Test.TcPOU
├── FB_MatrixGrow_Test.TcPOU
├── FB_MatrixInvert_Test.TcPOU
├── FB_MatrixMatrixProduct_Test.TcPOU
├── FB_MatrixShrink_Test.TcPOU
├── FB_MatrixSubMatrix_Test.TcPOU
├── FB_MatrixTranspose_Test.TcPOU
├── FB_StaticMatrix_Test.TcPOU
├── FB_VectorCrossProduct_Test.TcPOU
└── PRG_TEST.TcPOU
├── TcMatrixTest.plcproj
└── Version
└── Global_Version.TcGVL
/.gitignore:
--------------------------------------------------------------------------------
1 | # gitignore template for TwinCAT3
2 | # website: https://www.beckhoff.com/twincat3/
3 | #
4 | # Recommended: VisualStudio.gitignore
5 |
6 | # TwinCAT files
7 | *.tpy
8 | *.tclrs
9 | *.compiled-library
10 | *.compileinfo
11 | *.tmc
12 | *.tmcRefac
13 | *.library
14 | *.project.~u
15 | *.tsproj.bak
16 | *.xti.bak
17 | LineIDs.dbg
18 | LineIDs.dbg.bak
19 | _Boot/
20 | _CompileInfo/
21 | _Libraries/
22 |
23 | ## Ignore Visual Studio temporary files, build results, and
24 | ## files generated by popular Visual Studio add-ons.
25 | ##
26 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
27 |
28 | # User-specific files
29 | *.rsuser
30 | *.suo
31 | *.user
32 | *.userosscache
33 | *.sln.docstates
34 |
35 | # User-specific files (MonoDevelop/Xamarin Studio)
36 | *.userprefs
37 |
38 | # Mono auto generated files
39 | mono_crash.*
40 |
41 | # Build results
42 | [Dd]ebug/
43 | [Dd]ebugPublic/
44 | [Rr]elease/
45 | [Rr]eleases/
46 | x64/
47 | x86/
48 | [Aa][Rr][Mm]/
49 | [Aa][Rr][Mm]64/
50 | bld/
51 | [Bb]in/
52 | [Oo]bj/
53 | [Ll]og/
54 | [Ll]ogs/
55 |
56 | # Visual Studio 2015/2017 cache/options directory
57 | .vs/
58 | # Uncomment if you have tasks that create the project's static files in wwwroot
59 | #wwwroot/
60 |
61 | # Visual Studio 2017 auto generated files
62 | Generated\ Files/
63 |
64 | # MSTest test Results
65 | [Tt]est[Rr]esult*/
66 | [Bb]uild[Ll]og.*
67 |
68 | # NUnit
69 | *.VisualState.xml
70 | TestResult.xml
71 | nunit-*.xml
72 |
73 | # Build Results of an ATL Project
74 | [Dd]ebugPS/
75 | [Rr]eleasePS/
76 | dlldata.c
77 |
78 | # Benchmark Results
79 | BenchmarkDotNet.Artifacts/
80 |
81 | # .NET Core
82 | project.lock.json
83 | project.fragment.lock.json
84 | artifacts/
85 |
86 | # StyleCop
87 | StyleCopReport.xml
88 |
89 | # Files built by Visual Studio
90 | *_i.c
91 | *_p.c
92 | *_h.h
93 | *.ilk
94 | *.meta
95 | *.obj
96 | *.iobj
97 | *.pch
98 | *.pdb
99 | *.ipdb
100 | *.pgc
101 | *.pgd
102 | *.rsp
103 | *.sbr
104 | *.tlb
105 | *.tli
106 | *.tlh
107 | *.tmp
108 | *.tmp_proj
109 | *_wpftmp.csproj
110 | *.log
111 | *.vspscc
112 | *.vssscc
113 | .builds
114 | *.pidb
115 | *.svclog
116 | *.scc
117 |
118 | # Chutzpah Test files
119 | _Chutzpah*
120 |
121 | # Visual C++ cache files
122 | ipch/
123 | *.aps
124 | *.ncb
125 | *.opendb
126 | *.opensdf
127 | *.sdf
128 | *.cachefile
129 | *.VC.db
130 | *.VC.VC.opendb
131 |
132 | # Visual Studio profiler
133 | *.psess
134 | *.vsp
135 | *.vspx
136 | *.sap
137 |
138 | # Visual Studio Trace Files
139 | *.e2e
140 |
141 | # TFS 2012 Local Workspace
142 | $tf/
143 |
144 | # Guidance Automation Toolkit
145 | *.gpState
146 |
147 | # ReSharper is a .NET coding add-in
148 | _ReSharper*/
149 | *.[Rr]e[Ss]harper
150 | *.DotSettings.user
151 |
152 | # TeamCity is a build add-in
153 | _TeamCity*
154 |
155 | # DotCover is a Code Coverage Tool
156 | *.dotCover
157 |
158 | # AxoCover is a Code Coverage Tool
159 | .axoCover/*
160 | !.axoCover/settings.json
161 |
162 | # Visual Studio code coverage results
163 | *.coverage
164 | *.coveragexml
165 |
166 | # NCrunch
167 | _NCrunch_*
168 | .*crunch*.local.xml
169 | nCrunchTemp_*
170 |
171 | # MightyMoose
172 | *.mm.*
173 | AutoTest.Net/
174 |
175 | # Web workbench (sass)
176 | .sass-cache/
177 |
178 | # Installshield output folder
179 | [Ee]xpress/
180 |
181 | # DocProject is a documentation generator add-in
182 | DocProject/buildhelp/
183 | DocProject/Help/*.HxT
184 | DocProject/Help/*.HxC
185 | DocProject/Help/*.hhc
186 | DocProject/Help/*.hhk
187 | DocProject/Help/*.hhp
188 | DocProject/Help/Html2
189 | DocProject/Help/html
190 |
191 | # Click-Once directory
192 | publish/
193 |
194 | # Publish Web Output
195 | *.[Pp]ublish.xml
196 | *.azurePubxml
197 | # Note: Comment the next line if you want to checkin your web deploy settings,
198 | # but database connection strings (with potential passwords) will be unencrypted
199 | *.pubxml
200 | *.publishproj
201 |
202 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
203 | # checkin your Azure Web App publish settings, but sensitive information contained
204 | # in these scripts will be unencrypted
205 | PublishScripts/
206 |
207 | # NuGet Packages
208 | *.nupkg
209 | # NuGet Symbol Packages
210 | *.snupkg
211 | # The packages folder can be ignored because of Package Restore
212 | **/[Pp]ackages/*
213 | # except build/, which is used as an MSBuild target.
214 | !**/[Pp]ackages/build/
215 | # Uncomment if necessary however generally it will be regenerated when needed
216 | #!**/[Pp]ackages/repositories.config
217 | # NuGet v3's project.json files produces more ignorable files
218 | *.nuget.props
219 | *.nuget.targets
220 |
221 | # Microsoft Azure Build Output
222 | csx/
223 | *.build.csdef
224 |
225 | # Microsoft Azure Emulator
226 | ecf/
227 | rcf/
228 |
229 | # Windows Store app package directories and files
230 | AppPackages/
231 | BundleArtifacts/
232 | Package.StoreAssociation.xml
233 | _pkginfo.txt
234 | *.appx
235 | *.appxbundle
236 | *.appxupload
237 |
238 | # Visual Studio cache files
239 | # files ending in .cache can be ignored
240 | *.[Cc]ache
241 | # but keep track of directories ending in .cache
242 | !?*.[Cc]ache/
243 |
244 | # Others
245 | ClientBin/
246 | ~$*
247 | *~
248 | *.dbmdl
249 | *.dbproj.schemaview
250 | *.jfm
251 | *.pfx
252 | *.publishsettings
253 | orleans.codegen.cs
254 |
255 | # Including strong name files can present a security risk
256 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
257 | #*.snk
258 |
259 | # Since there are multiple workflows, uncomment next line to ignore bower_components
260 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
261 | #bower_components/
262 |
263 | # RIA/Silverlight projects
264 | Generated_Code/
265 |
266 | # Backup & report files from converting an old project file
267 | # to a newer Visual Studio version. Backup files are not needed,
268 | # because we have git ;-)
269 | _UpgradeReport_Files/
270 | Backup*/
271 | UpgradeLog*.XML
272 | UpgradeLog*.htm
273 | ServiceFabricBackup/
274 | *.rptproj.bak
275 |
276 | # SQL Server files
277 | *.mdf
278 | *.ldf
279 | *.ndf
280 |
281 | # Business Intelligence projects
282 | *.rdl.data
283 | *.bim.layout
284 | *.bim_*.settings
285 | *.rptproj.rsuser
286 | *- [Bb]ackup.rdl
287 | *- [Bb]ackup ([0-9]).rdl
288 | *- [Bb]ackup ([0-9][0-9]).rdl
289 |
290 | # Microsoft Fakes
291 | FakesAssemblies/
292 |
293 | # GhostDoc plugin setting file
294 | *.GhostDoc.xml
295 |
296 | # Node.js Tools for Visual Studio
297 | .ntvs_analysis.dat
298 | node_modules/
299 |
300 | # Visual Studio 6 build log
301 | *.plg
302 |
303 | # Visual Studio 6 workspace options file
304 | *.opt
305 |
306 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
307 | *.vbw
308 |
309 | # Visual Studio LightSwitch build output
310 | **/*.HTMLClient/GeneratedArtifacts
311 | **/*.DesktopClient/GeneratedArtifacts
312 | **/*.DesktopClient/ModelManifest.xml
313 | **/*.Server/GeneratedArtifacts
314 | **/*.Server/ModelManifest.xml
315 | _Pvt_Extensions
316 |
317 | # Paket dependency manager
318 | .paket/paket.exe
319 | paket-files/
320 |
321 | # FAKE - F# Make
322 | .fake/
323 |
324 | # CodeRush personal settings
325 | .cr/personal
326 |
327 | # Python Tools for Visual Studio (PTVS)
328 | __pycache__/
329 | *.pyc
330 |
331 | # Cake - Uncomment if you are using it
332 | # tools/**
333 | # !tools/packages.config
334 |
335 | # Tabs Studio
336 | *.tss
337 |
338 | # Telerik's JustMock configuration file
339 | *.jmconfig
340 |
341 | # BizTalk build output
342 | *.btp.cs
343 | *.btm.cs
344 | *.odx.cs
345 | *.xsd.cs
346 |
347 | # OpenCover UI analysis results
348 | OpenCover/
349 |
350 | # Azure Stream Analytics local run output
351 | ASALocalRun/
352 |
353 | # MSBuild Binary and Structured Log
354 | *.binlog
355 |
356 | # NVidia Nsight GPU debugger configuration file
357 | *.nvuser
358 |
359 | # MFractors (Xamarin productivity tool) working folder
360 | .mfractor/
361 |
362 | # Local History for Visual Studio
363 | .localhistory/
364 |
365 | # BeatPulse healthcheck temp database
366 | healthchecksdb
367 |
368 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
369 | MigrationBackup/
370 |
371 | # Ionide (cross platform F# VS Code tools) working folder
372 | .ionide/
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 BurksEngineering
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 | # TcMatrix
2 |
3 | ## Description
4 |
5 | A TwinCAT 3 library for manipulating 2D data sets of LREAL.
6 |
7 | Features include:
8 |
9 | * Element-wise setting, getting, summing, scaling, and power functions
10 | * Initialization as copies, zeros, trapezoidal, and other pre-defined matrix types
11 | * Matrix operations like multiplication, transposition, and inversion
12 | * Vector operations for 1D matricies like dot/cross product and normalization
13 | * Complex access operations similar to ['slicing'](https://en.wikipedia.org/wiki/Array_slicing)
14 | * Options to use static or dynamically allocated memory
15 | * Reading/Writing with CSV files, output to the ADS message logger
16 |
17 | Compare to:
18 |
19 | * [CODESYS Matrix Library](https://us.store.codesys.com/matrix-library.html) ([docs](https://store.codesys.com/media/n98_media_assets/files/2111000003-D/4/Matrix%20Bibliothek_en.pdf))
20 | * [Siemens Library of General Functions](https://support.industry.siemens.com/cs/document/109479728/library-of-general-functions-(lgf)-for-simatic-step-7-(tia-portal)-and-simatic-s7-1200-s7-1500) ([docs](https://cache.industry.siemens.com/dl/files/728/109479728/att_1019474/v3/109479728_LGF_TIAV16_DOC_V5_0_0_en.pdf))
21 |
22 | ## Contents
23 |
24 | * [Installation](#twincat-3-installation)
25 | * [Usage](#usage)
26 | * [Quick Start](#quick-start)
27 | * [Matrix](#base-matrix-class)
28 | * [DynamicMatrix](#dynamicmatrix-class)
29 | * [StaticMatrix](#static-memory-matrix)
30 | * [MatrixAccessor](#matrix-accessors)
31 | * [Examples](#examples)
32 | * [Projects](#projects-with-implementations)
33 |
34 | ## TwinCAT 3 Installation
35 |
36 | ### From Binary
37 |
38 | 1. Go to the [releases page](https://github.com/BurksEngineering/TcMatrix/releases) and download the *.library file from the latest release, saving it to a temporary directory somewhere on the computer running TwinCAT.
39 | 1. Follow the [library installation instructions](https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_plc_intro/4189333259.html) from Beckhoff, using the 'Install' option and browsing for the local copy you had just downloaded.
40 | 1. After installtion, you may delete the local copy of the library that you had downloaded. Beckhoff has likely copied it to a version-specific folder in `C:\TwinCAT\3.1\Components\Plc\Managed Libraries\Burks Engineering\TcMatrix\`
41 |
42 | ### From Source
43 |
44 | Preconditions:
45 |
46 | * TwinCAT 3.1.4024 XAE
47 | * TwinCAT 3.1.4024 XAR, ideally configured with an isolated core
48 | * Visual Studio Community or Shell, 2019 or higher
49 | * [TcUnit](https://github.com/tcunit/TcUnit) v1.2 or higher
50 |
51 | Compilation:
52 |
53 | 1. Clone the repository to a computer running TwinCAT 3
54 | 1. Open the [main solution file](TcMatrix.sln) in Visual Studio
55 | 1. Within the Visual Studio *TcMatrix* project, right click on the *TcMatrix/TcMatrix Project* item and select *Rebuild*
56 | 1. There should be no compile errors, although there may be warnings
57 | 1. Right click on the *TcMatrix/TcMatrix Project* item again and select *Save as library and install*
58 | 1. The file can be saved anywhere, but a local *Builds* folder is always a good choice
59 |
60 | Test:
61 |
62 | 1. Within the Visual Studio *TcMatrixTest* project, right click on the *PLC/TcMatrixTest/TcMatrixTest Project* item and select *Rebuild*
63 | 1. There should be no compile errors, although there may be warnings
64 | 1. Open the *SYSTEM/Real-Time* item and click *Read From Target*, then assign all tasks to an isolated core from your system
65 | 1. In the Visual Studio toolbar (or TwinCAT file menu) click *Activate Configuration*
66 | 1. When prompted, agree to start the project in run mode and auto-start the boot project
67 | 1. After a few seconds the TcUnit results should be visible in the Error List window. Verify that all tests have passed.
68 |
69 | ## Usage
70 |
71 | ### Quick Start
72 |
73 | Example showing vector multiplication with the identity matrix.
74 | See TcMatrixTest.FB_Array_Test.MarkdownExample1
75 | ```
76 | VAR
77 | M : Array2DStaticMatrix; //This instance is the matrix that the code will interact with
78 | M_Data : ARRAY[1..3,1..3] OF LREAL; //This array will act as the memory for the matrix
79 | V : Array2DStaticMatrix; //This instance is the initial column vector
80 | V_Data : ARRAY[1..3,1..1] OF LREAL := [1, 2, 3]; //This array will act as the memory for the initial column vector, prepopulated
81 | Res : Array2DStaticMatrix; //This instance is the resulting column vector
82 | Res_Data : ARRAY[1..3,1..1] OF LREAL := [1, 2, 3]; //This array will act as the memory for the resulting column vector
83 | success : BOOL; //records success or failure of the matrix multiplication
84 | equal : BOOL; //records success if the resulting vector is equal to the first
85 | END_VAR
86 |
87 | M(Data := M_Data); //Connect the memory to the matrix and initialize it
88 | V(Data := V_Data); //Connect the memory to the initial column vector and initialize it (retaining declared values)
89 | Res(Data := Res_Data); //Connect the memory to the resulting column vector and initialize it
90 |
91 | M.FillTrapezoidal(Diagonal := 1, UpperRight := 0, LowerLeft := 0); //Transforms the matrix from all zeros into the identity matrix
92 | success := Matrix_Product(M,V,Res); //perform the matrix multiplication
93 | equal := V.IsEqual(Res); //the result of the multiplication should be equal to the initial value because of the identity matrix
94 |
95 | ```
96 |
97 | ### Base Matrix Class
98 |
99 | This abstract FB is the basis for all other matrix FBs.
100 | It represents a 2D array of LREAL elements.
101 | It provides dozens of methods and properties useful for manipulating itself, calculating values, and comparing to other matricies.
102 | Critically, this base class does not actually contain any mechanism for storing the values of the matrix (that is the responsibility of the specific inheriting sub-class).
103 |
104 | ---
105 | **NOTE**
106 |
107 | Because *Matrix* is an abstract FB it cannot be assigned (`:=`) directly.
108 | Instead, each *Matrix* is always passed in and out of a function *AS REFERENCE*.
109 | This also allows interactions with inhereted sub-classes of *Matrix* more easily.
110 |
111 | ---
112 |
113 | Below are some (but not all) of the functions and methods within the base Matrix FB. All functions and methods are documented within the library and can be explored within TwinCAT.
114 |
115 | #### Element Access
116 |
117 | Fundamentally the matrix is just a 2D array of LREAL data. These simple methods and functions form the backbone of the entire class.
118 |
119 | * __Rows__ : returns the number of rows in the matrix
120 | * __Cols__ : Returns the number of columns in the matrix
121 | * __Size(dim)__ : Returns the length of the matrix in the specified dimension (0=rows, 1=cols)
122 | * __GetRC(R,C)__ : Returns the value of the element at the specified (0-indexed) position within the matrix
123 | * __SetRC(R,C,Val)__ : Sets the value of the element at the specified (0-indexed) position within the matrix
124 | * __IsEmpty__ : Returns TRUE if *Rows*=0 OR *Cols*=0
125 | * __IsSquare__ : Returns TRUE if *Rows*=*Cols* and the matrix is not empty
126 | * __IsVector__ : Returns TRUE if *Rows*=1 OR *Cols*=1 and the matrix is not empty
127 |
128 | Every *Matrix* is considered as a 1D array of LREAL data types under the hood.
129 | This 1D view of data can be particularly useful when considering the matrix as a vector, but not caring whether it is a row vector or column vector.
130 |
131 | * __Length__ : The length of the 1D array (equal to *Rows* x *Cols*)
132 | * __GetI(I)__ : Returns the value of the element at the specified (0-based) position in the 1D array
133 | * __SetI(I,Val)__ : Sets the value of the element at the specified (0-based) position in the 1D array
134 |
135 | #### Initializers
136 |
137 | * __Clear()__ : Sets the value of every element to 0.0
138 | * __CopyFrom(Matrix)__ : Only if the supplied matrix is exactly the same size as this matrix, copy all elements to this matrix
139 | * __FillFrom(Matrix)__ : Copy every element from the supplied matrix which exists in both this amtrix and the supplied matrix
140 | * __FillTrapezoidal(D,UR,LL)__ : Copy one value into the main diagonal of this matrix, copy another value into all elements to the upper-right of the main diagonal, and copy another value into all elements to the lower-left of the main diagonal
141 |
142 | #### Modifiers
143 |
144 | * __ElementSum(Matrix)__ : Sets each element of this matrix to the value of its sum with the corresponding element in the supplied matrix
145 | * __ElementDifference(Matrix)__ : Sets each element of this matrix (as subtrahend) to the value of its difference with the corresponding element in the supplied matrix (as minuend)
146 | * __ElementProduct(Matrix)__ : Sets each element of this matrix to the value of its product with the corresponding element in the supplied matrix
147 | * __Scale(Scalar)__ : Sets each element of this matrix to the value of its product with the specified scalar
148 | * __Power(Exponent)__ : Sets each element of this matrix to the value of itsself raised to the supplied exponent
149 | * __TransposeSquare()__ : (Works on square matricies only) Swaps each element at (R,C) with a corresponding element at (C,R)
150 | * __InvertSquare(Tolerance)__ : Transforms this matrix into its inverse, if possible. The supplied Tolerance is used as a limit for any number used as a denominator (1E-12 is a good value to use).
151 | * __SortByColAsc(C)__ : Sorts the matrix by swapping entire rows around until the specified column is in ascending order. The relative position of equal rows will remain unchanged so as to allow tiered sorting.
152 |
153 | #### Comparators
154 |
155 | * __IsEqualSize__ : Returns TRUE if this matrix is the same size (*Rows* and *Cols*) as the supplied matrix
156 | * __IsEqual__ : Returns TRUE if *IsEqualSize* is true AND every element in this matrix is equal to its corresponding element in the supplied matrix
157 | * __IsNearlyEqual(Tolerance)__ : Returns TRUE if *IsEqualSize* AND every element in this matrix is equal (within the specified tolerance) to its corresponding element in the supplied matrix
158 |
159 | #### Calculators
160 |
161 | * __Sum__ : A property that returns the sum of every element in the matrix
162 | * __MaxVal__ : A property that returns the maximum value contained in the matrix
163 | * __MinVal__ : A property that returns the minimum value contained in the matrix
164 | * __Average__ : A property that returns the average of all values contained in the matrix
165 | * __GetDeterminate()__ : Calculates the determinate of the matrix if it is square
166 | * __GetVectorMagnitude()__ : Calculates the magnitude (square root of the sum of the squares) of the matrix if it is a vector
167 |
168 | #### External Functions
169 |
170 | These functions compartmentalize simple matrix operations outside of any specific FB.
171 | For some operations, like matrix multiplication, the dimensions of every *Matrix* involved can be different which makes using an external function more convenient for non-resizeable matricies.
172 | They all take in *REFERENCE TO Matrix* as both the inputs and outputs to their arithmatic operation.
173 | Be careful when using a reference to the same *Matrix* instance as both an input and an output!
174 |
175 | A non-exhaustive list of included external functions (see documentation within TwinCAT for the full list):
176 |
177 | * __Matrix_Product__
178 | * __Matrix_Transpose__
179 | * __Matrix_Grow__
180 | * __Matrix_Shrink__
181 | * __Matrix_SubMatrix__
182 | * __Vector_CrossProduct__
183 |
184 | #### Inheritance Guide
185 |
186 | To make a concrete matrix class as a sub-class of the *Matrix* FB the following properties and methods must be implemented:
187 |
188 | * __Rows__ : *UINT*
189 | * __Cols__ : *UINT*
190 | * __GetI(I)__ : *LREAL*
191 | * __SetI(I,Val)__ : *BOOL*
192 |
193 | Because everything comes back to representing a 1D array of LREALs as a 2D array of LREALs all you need are these four functions.
194 | The *Rows* and *Cols* together define the length of the 1D array and the size of the 2D array.
195 | The *GetI* and *SetI* functions define the transformation between the 1D and 2D array, as well as access to the source of the 1D data.
196 | This type of interface also allows for a *Matrix* itself to be the source data for another *Matrix*! (see [Matrix Accessors](#matrix-accessors))
197 |
198 | Example Inheritance:
199 | * __*DynamicMatrix*__ uses a *POINTER TO LREAL* assigned from dynamic memory allocation to track the 1D data
200 | * __*ExternalStaticMatrix*__ uses a *POINTER TO LREAL* assigned at initialization based on some external *ARRAY [] OF LREAL*
201 | * __*MatrixAccessor*__ uses a *REFERENCE TO Matrix* assigned at runtime as the basis for the memory and structure
202 |
203 | #### CSV File Interaction
204 |
205 | The *MatrixCsvReader* and *MatrixCsvWriter* FBs exist to help read/write data from/to CSV files on the disk of the local IPC.
206 | Headers must be supplied externally when writing, and are ignored when reading.
207 | When reading a CSV file the destination matrix must be large enough to fit the entire contents of the file.
208 | The functions take multiple PLC cycles to complete, and work like a standard multi-cylce FB (bExecute, bError, etc).
209 | See the included documentaiton within TwinCAT for details.
210 |
211 | ### DynamicMatrix Class
212 |
213 | The *DynamicMatrix* class uses the *FB_DynMem_Manager2* to dynamically allocate as much memory as required for the given operation.
214 | This amazing flexibility comes at the cost of some restrictions on use in order to avoid memory leaks.
215 |
216 | ---
217 | **WARNING**
218 |
219 | Using the assignment operator (`:=`) to copy a *DynamicMatrix* will result in the new matrix retaining a pointer to the data of the old matrix!
220 | For this reason, the pragma `{attribute 'no_assign'}` is used to block assignment at compile-time, but inheriting sub-classes will need to include this pragma themselves.
221 | Note that using *DynamicMatrix* as the return value of a function is essentially an assignment operation and will also not work.
222 | Therefore, it is recommended to always pass *DynamicMatrix* objects in and out of functions using the *REFERENCE TO* keyword.
223 | To alleviate the pain of these assignment rules there are a ton of '[Resultant](#resultants)' helper functions available to use which initialize a new *DynamicMatrix* as the result of some operation on other matrix objects.
224 |
225 | ---
226 |
227 | The *DynamicMatrix* FB will automatically free its memory when an instance of the class is created, or goes out of scope.
228 | This prevents memory leaks and page faults, but it also prevents you from instantiating a *DynamicMatrix* inside of a function and then passing a *REFERENCE TO* it back up the call chain.
229 | Another consequnce is that a *DynamicMatrix* cannot be retained after power-loss.
230 | A *DynamicMatrix* within a GVL will free its memory when the program terminates.
231 |
232 | #### Initializers
233 |
234 | All of these functions destroy any data already in the matrix and replace it with the new data.
235 |
236 | * __Free()__ : Frees all dynamically allocated memory and resets the size of the matrix to 0x0
237 | * __Init(R,C)__ : Initializes a *R*x*C* matrix, with potentially random non-zero values
238 | * __InitZeros(R,C)__ : Initializes a *R*x*C* matrix where every element is equal to 0.0
239 | * __InitVector(L,Val,Inc)__ : Initializes an *L*x1 column vector where the 0th element is equal to *Val* and every subsequent element is *Inc* larger than the previous
240 | * __InitCopy(Matrix)__ : Initializes a matrix with the exact size and contents of the supplied matrix
241 | * __InitIdentity(L)__ : Initializes a square identity matrix of size *L*x*L*
242 | * __InitConstant(R,C,Val)__ : Initializes a *R*x*C* matrix where every element is equal to the supplied value
243 | * __InitTrapezoidal(R,C,D,UR,LL)__ : Initializes a *R*x*C* matrix then fills is using *FillTrapezoidal()*
244 |
245 | #### Dynamic Modifiers
246 |
247 | All of these function change the dimensions *Rows* and *Cols*) of the matrix without destroying the data within the matrix.
248 |
249 | * __Resize(R,C,Retain?,Init?)__ : Changes the total number of *Rows* and *Cols* in the matrix.
250 | If Retain is seleced then any element within the bounds of both the initial and resulting matrix will have its value retained.
251 | If Init is selected then any newly created element will have its value set to zero.
252 | * __Transpose()__ : Similar to *TransposeSquare()*, however it works on rectangular matricies (swapping *Rows* and *Cols*)
253 | * __Shrink(R,C)__ : Removes the specified Row and Column from the matrix, resuling in a new size of (*Rows*-1,*Cols*-1). No dimension can be shrunk from 1 to 0 (therefore vectors only shrink in one direction).
254 | * __Grow(R,C,Dval,Rval,Cval)__ : Adds a row and column in the specified positions. The value of the new element at the intersection is specified by DVal, while the values in the newly created Row and Column are specified by Rval and Cval, respectively.
255 |
256 | #### Resultants
257 |
258 | There are many functions available that initialzie the size and contents of a *DynamicMatrix* to the result of another function (typically a [modifier](#modifiers) or an [external function](#external-functions))
259 |
260 | A non-exhaustive list of resultant functions (see documentation within TwinCAT for the full list):
261 |
262 | * __AsElementSum__
263 | * __AsInverse__
264 | * __AsMatrixProduct__
265 | * __AsVectorCrossProduct__
266 | * __AsSubMatrix__
267 | * __AsRowVector__
268 | * __AsColVector__
269 |
270 | ### Static Memory Matrix
271 |
272 | This type of matrix has the number of rows and columns set during initialization and then they cannot be changed.
273 |
274 | #### Base StaticMatrix Class
275 |
276 | This simple abstract class sets the rules for all static memory matricies by creating a protected *Init_(R,C)* method that must be called to set the initial size of the matrix.
277 | It also implements the required *Rows* and *Cols* properties to return the values that were set during initialization.
278 |
279 | #### ExternalStaticMatrix Class
280 |
281 | This simple concrete derivative of the StaticMatrix class uses an external *ARRAY OF LREAL* as the memory source for the matrix data.
282 | It is accessed in row-major order based on the logic in the *GetI* and *SetI* functions.
283 | It is most useful when someone doesn't trust dynamically allocated memory, but also doesn't want to make multiple size-specific custom derived FBs just to set up a single complex matrix operation.
284 |
285 | * __Init(R,C,pD)__ : Must be called in order to setup the matrix (it will be empty until this method is called).
286 |
287 | #### Array2DStaticMatrix Class
288 |
289 | This simple concrete derivative of the StaticMatrix class uses an external *2D ARRAY OF LREAL* as the memory source for the matrix data.
290 | It is most useful when someone is already interfacing with data in a native 2D array, but wants to quickly utilize some matrix functions.
291 |
292 | * To set up the matrix, the main FB must be called with the __Data__ parameter pointing at the external 2D array of LREAL that will be treated like a matrix.
293 |
294 | ---
295 | **WARNING**
296 |
297 | It is the callers responsibility to ensure that the pointer provided to the initializer is valid:
298 |
299 | * The length of the data structure pointed to (probably an array of LREAL) is at least as long as *Rows* x *Cols*
300 | * The scope of the data structure pointed to is the same as the scope of the corresponding *ExternalStaticMatrix* (probably declared adjacent to eachother as a VAR or GVL)
301 |
302 | Additionally, direct assignment (`:=`) should not be used with this type of matrix because a second copy of the Matrix, but with a pointer to the original's data source, would be created.
303 | For this reason, the pragma `{attribute 'no_assign'}` is used to block assignment at compile-time.
304 | Keep in mind that returning a value from a function is also a form of assignment and is not allowed.
305 |
306 | ---
307 |
308 | ### Matrix Accessors
309 |
310 | Matrix accessors are a way of interacting with the data of a parent *Matrix* through a special lens, without copying the data into a new *Matrix* and then back again.
311 | This type of *Matrix* works by creating a function that converts the I-based indexing of the accessor matrix into the I-based indexing of the parent matrix, then using it to intercept calls to *GetI* and *SetI*.
312 | Concrete Matrix Accessor Classes can be easily created from the parent MatrixAccessor abstract class by implementing the This2Parent method in order to define the index conversion.
313 | Note that matrix accessor allow **both read and write access** to the parent matrix!
314 |
315 | Included Matrix Accessors:
316 |
317 | * __SubMatrixAccessor__ : Allows access to a rectangular subset of the parent matrix as if it were a standalone matrix
318 | * __TransposeMatrixAccessor__ : Allows access to the elements of the parent matrix as if it were transposed
319 | * __ShrunkMatrixAccessor__ : Allows access to the parent matrix as if the [*Shrink* function](#dynamic-modifiers) had been called
320 |
321 | ---
322 | **WARNING**
323 |
324 | Matrix Accessors inherently store a pointer (*BY REFERENCE*) to their parent matrix.
325 | If the parent matrix goes out of scope (through function return) or is moved (through an online change) then the Matrix Accessor will no longer work.
326 | Therefore, they are best used quickly then destroyed, all within the scope of a single F or FB.
327 |
328 | ---
329 |
330 | ## Examples
331 |
332 | ### Projects With Implementations
333 |
334 | * [TcTransform](https://github.com/BurksEngineering/TcTransform): Static memory 3x1, 3x3, and 4x4 matricies for common 3D coordinate system transformations
335 | * The unit tests within this project provide a large number of simple examples and usages
336 | * The ExternalStaticMatrix is one example of how to implement the StaticMatrix base class
--------------------------------------------------------------------------------
/TcMatrix.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.31605.320
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{B1E792BE-AA5F-4E3C-8C82-674BF9C0715B}") = "TcMatrixTest", "TcMatrixTest\TcMatrixTest.tsproj", "{E21DD48F-97CD-43F0-AA17-4340951B180B}"
7 | EndProject
8 | Project("{DFBE7525-6864-4E62-8B2E-D530D69D9D96}") = "TcMatrix", "TcMatrix\TcMatrix.tspproj", "{85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{CFB45DAA-19B9-4B68-BFD0-1FD493283908}"
11 | ProjectSection(SolutionItems) = preProject
12 | LICENSE = LICENSE
13 | README.md = README.md
14 | EndProjectSection
15 | EndProject
16 | Global
17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
18 | Debug|TwinCAT CE7 (ARMV7) = Debug|TwinCAT CE7 (ARMV7)
19 | Debug|TwinCAT OS (ARMT2) = Debug|TwinCAT OS (ARMT2)
20 | Debug|TwinCAT RT (x64) = Debug|TwinCAT RT (x64)
21 | Debug|TwinCAT RT (x86) = Debug|TwinCAT RT (x86)
22 | Release|TwinCAT CE7 (ARMV7) = Release|TwinCAT CE7 (ARMV7)
23 | Release|TwinCAT OS (ARMT2) = Release|TwinCAT OS (ARMT2)
24 | Release|TwinCAT RT (x64) = Release|TwinCAT RT (x64)
25 | Release|TwinCAT RT (x86) = Release|TwinCAT RT (x86)
26 | EndGlobalSection
27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
28 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Debug|TwinCAT CE7 (ARMV7).ActiveCfg = Debug|TwinCAT CE7 (ARMV7)
29 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Debug|TwinCAT CE7 (ARMV7).Build.0 = Debug|TwinCAT CE7 (ARMV7)
30 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Debug|TwinCAT OS (ARMT2).ActiveCfg = Debug|TwinCAT OS (ARMT2)
31 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Debug|TwinCAT OS (ARMT2).Build.0 = Debug|TwinCAT OS (ARMT2)
32 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Debug|TwinCAT RT (x64).ActiveCfg = Debug|TwinCAT RT (x64)
33 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Debug|TwinCAT RT (x64).Build.0 = Debug|TwinCAT RT (x64)
34 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Debug|TwinCAT RT (x86).ActiveCfg = Debug|TwinCAT RT (x86)
35 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Debug|TwinCAT RT (x86).Build.0 = Debug|TwinCAT RT (x86)
36 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Release|TwinCAT CE7 (ARMV7).ActiveCfg = Release|TwinCAT CE7 (ARMV7)
37 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Release|TwinCAT CE7 (ARMV7).Build.0 = Release|TwinCAT CE7 (ARMV7)
38 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Release|TwinCAT OS (ARMT2).ActiveCfg = Release|TwinCAT OS (ARMT2)
39 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Release|TwinCAT OS (ARMT2).Build.0 = Release|TwinCAT OS (ARMT2)
40 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Release|TwinCAT RT (x64).ActiveCfg = Release|TwinCAT RT (x64)
41 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Release|TwinCAT RT (x64).Build.0 = Release|TwinCAT RT (x64)
42 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Release|TwinCAT RT (x86).ActiveCfg = Release|TwinCAT RT (x86)
43 | {E21DD48F-97CD-43F0-AA17-4340951B180B}.Release|TwinCAT RT (x86).Build.0 = Release|TwinCAT RT (x86)
44 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Debug|TwinCAT CE7 (ARMV7).ActiveCfg = Debug|TwinCAT CE7 (ARMV7)
45 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Debug|TwinCAT CE7 (ARMV7).Build.0 = Debug|TwinCAT CE7 (ARMV7)
46 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Debug|TwinCAT OS (ARMT2).ActiveCfg = Debug|TwinCAT OS (ARMT2)
47 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Debug|TwinCAT OS (ARMT2).Build.0 = Debug|TwinCAT OS (ARMT2)
48 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Debug|TwinCAT RT (x64).ActiveCfg = Debug|TwinCAT RT (x64)
49 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Debug|TwinCAT RT (x64).Build.0 = Debug|TwinCAT RT (x64)
50 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Debug|TwinCAT RT (x86).ActiveCfg = Debug|TwinCAT RT (x86)
51 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Debug|TwinCAT RT (x86).Build.0 = Debug|TwinCAT RT (x86)
52 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Release|TwinCAT CE7 (ARMV7).ActiveCfg = Release|TwinCAT CE7 (ARMV7)
53 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Release|TwinCAT CE7 (ARMV7).Build.0 = Release|TwinCAT CE7 (ARMV7)
54 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Release|TwinCAT OS (ARMT2).ActiveCfg = Release|TwinCAT OS (ARMT2)
55 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Release|TwinCAT OS (ARMT2).Build.0 = Release|TwinCAT OS (ARMT2)
56 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Release|TwinCAT RT (x64).ActiveCfg = Release|TwinCAT RT (x64)
57 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Release|TwinCAT RT (x64).Build.0 = Release|TwinCAT RT (x64)
58 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Release|TwinCAT RT (x86).ActiveCfg = Release|TwinCAT RT (x86)
59 | {85BE87FF-93A2-4C73-967A-8A4C6B2B95E6}.Release|TwinCAT RT (x86).Build.0 = Release|TwinCAT RT (x86)
60 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Debug|TwinCAT CE7 (ARMV7).ActiveCfg = Debug|TwinCAT CE7 (ARMV7)
61 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Debug|TwinCAT CE7 (ARMV7).Build.0 = Debug|TwinCAT CE7 (ARMV7)
62 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Debug|TwinCAT OS (ARMT2).ActiveCfg = Debug|TwinCAT OS (ARMT2)
63 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Debug|TwinCAT OS (ARMT2).Build.0 = Debug|TwinCAT OS (ARMT2)
64 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Debug|TwinCAT RT (x64).ActiveCfg = Debug|TwinCAT RT (x64)
65 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Debug|TwinCAT RT (x64).Build.0 = Debug|TwinCAT RT (x64)
66 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Debug|TwinCAT RT (x86).ActiveCfg = Debug|TwinCAT RT (x86)
67 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Debug|TwinCAT RT (x86).Build.0 = Debug|TwinCAT RT (x86)
68 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Release|TwinCAT CE7 (ARMV7).ActiveCfg = Release|TwinCAT CE7 (ARMV7)
69 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Release|TwinCAT CE7 (ARMV7).Build.0 = Release|TwinCAT CE7 (ARMV7)
70 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Release|TwinCAT OS (ARMT2).ActiveCfg = Release|TwinCAT OS (ARMT2)
71 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Release|TwinCAT OS (ARMT2).Build.0 = Release|TwinCAT OS (ARMT2)
72 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Release|TwinCAT RT (x64).ActiveCfg = Release|TwinCAT RT (x64)
73 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Release|TwinCAT RT (x64).Build.0 = Release|TwinCAT RT (x64)
74 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Release|TwinCAT RT (x86).ActiveCfg = Release|TwinCAT RT (x86)
75 | {D894BF7B-783C-4A82-8AF1-3D395565C311}.Release|TwinCAT RT (x86).Build.0 = Release|TwinCAT RT (x86)
76 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Debug|TwinCAT CE7 (ARMV7).ActiveCfg = Debug|TwinCAT CE7 (ARMV7)
77 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Debug|TwinCAT CE7 (ARMV7).Build.0 = Debug|TwinCAT CE7 (ARMV7)
78 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Debug|TwinCAT OS (ARMT2).ActiveCfg = Debug|TwinCAT OS (ARMT2)
79 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Debug|TwinCAT OS (ARMT2).Build.0 = Debug|TwinCAT OS (ARMT2)
80 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Debug|TwinCAT RT (x64).ActiveCfg = Debug|TwinCAT RT (x64)
81 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Debug|TwinCAT RT (x64).Build.0 = Debug|TwinCAT RT (x64)
82 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Debug|TwinCAT RT (x86).ActiveCfg = Debug|TwinCAT RT (x86)
83 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Debug|TwinCAT RT (x86).Build.0 = Debug|TwinCAT RT (x86)
84 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Release|TwinCAT CE7 (ARMV7).ActiveCfg = Release|TwinCAT CE7 (ARMV7)
85 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Release|TwinCAT CE7 (ARMV7).Build.0 = Release|TwinCAT CE7 (ARMV7)
86 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Release|TwinCAT OS (ARMT2).ActiveCfg = Release|TwinCAT OS (ARMT2)
87 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Release|TwinCAT OS (ARMT2).Build.0 = Release|TwinCAT OS (ARMT2)
88 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Release|TwinCAT RT (x64).ActiveCfg = Release|TwinCAT RT (x64)
89 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Release|TwinCAT RT (x64).Build.0 = Release|TwinCAT RT (x64)
90 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Release|TwinCAT RT (x86).ActiveCfg = Release|TwinCAT RT (x86)
91 | {C0F4BEF7-55D3-4B7E-A92A-8580425ECFB1}.Release|TwinCAT RT (x86).Build.0 = Release|TwinCAT RT (x86)
92 | EndGlobalSection
93 | GlobalSection(SolutionProperties) = preSolution
94 | HideSolutionNode = FALSE
95 | EndGlobalSection
96 | GlobalSection(ExtensibilityGlobals) = postSolution
97 | SolutionGuid = {63919060-1A7C-4886-96B2-69C3753079AE}
98 | EndGlobalSection
99 | EndGlobal
100 |
--------------------------------------------------------------------------------
/TcMatrix/LibraryCategory.libcat.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | d5875a41-817d-44f3-8af7-6c59eaddc95f
5 | 1.0.0.0
6 | Burks
7 |
8 |
9 | 426a88ee-bb19-4918-8554-e1c9c24621f9
10 | 1.0.0.0
11 |
12 | d5875a41-817d-44f3-8af7-6c59eaddc95f
13 |
14 | Matrix
15 |
16 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix.tspproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix.tspproj.bak:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/Array2DStaticMatrix.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
21 |
22 |
25 |
26 |
27 |
28 |
42 |
43 | Ri,Col => Ci);
49 | IF Ri <0 OR Ri >= Rows OR Ci < 0 OR Ci >= Cols THEN
50 | GetI := 0.0;
51 | LogWarning('%s: Attempted I access outside of bounds of array');
52 | ELSE
53 | //add lower bound offset before fetching from array
54 | GetI := Data[R0+Ri,C0+Ci];
55 | END_IF
56 | END_IF]]>
57 |
58 |
59 |
60 |
72 |
73 | Ri,Col => Ci);
79 | IF Ri <0 OR Ri >= Rows OR Ci < 0 OR Ci >= Cols THEN
80 | SetI := FALSE;
81 | LogWarning('%s: Attempted I access outside of bounds of array');
82 | ELSE
83 | SetI := TRUE;
84 | Data[R0+Ri,C0+Ci] := Val;
85 | END_IF
86 | END_IF]]>
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/Csv/MatrixCsvReader.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
54 |
55 | = M.Rows OR Ci >= M.Cols THEN
148 | bError := TRUE;
149 | nErrId :=1;
150 | nErrStep := step;
151 | step := stepCloseFile;
152 | RETURN;
153 | END_IF
154 | M.SetRC(Ri,Ci,STRING_TO_LREAL(CsvRead.getValue));
155 | Ci := Ci + 1;
156 | nVals := NVals + 1;
157 | IF CsvRead.bCRLF THEN
158 | Ri := Ri + 1;
159 | Ci := 0;
160 | nRows := Ri;
161 | END_IF
162 | IF Ci > nCols THEN
163 | nCols := Ci;
164 | END_IF
165 | END_IF
166 | END_IF
167 | UNTIL
168 | NOT(CsvRead.bOk)
169 | END_REPEAT
170 | IF readEOF THEN//this probably will never happen because EOF seems to be mutually exclusive with reading bytes
171 | step := stepCloseFile;
172 | ELSE
173 | //move pointer backwards to where it was before the read, then forward based on how much data was read from the CSV buffer. This re-reads any partial cells that were not parsed
174 | FileSeek.nSeekPos := bytesParsed - bytesRead;
175 | IF FileSeek.nSeekPos <> 0 THEN
176 | step := stepMovePointer;
177 | ELSE
178 | step := stepFillBuffer;
179 | END_IF;
180 | END_IF
181 |
182 |
183 |
184 | stepMovePointer:
185 | IF FileSeek.bError AND NOT bError THEN
186 | bError := TRUE;
187 | nErrId := FileSeek.nErrId;
188 | nErrStep := step;
189 | step := stepDone;
190 | ELSIF NOT(FileSeek.bBusy) THEN
191 | step := stepFillBuffer;
192 | END_IF
193 |
194 | stepCloseFile:
195 |
196 | IF FileClose.bError AND NOT bError THEN
197 | bError := TRUE;
198 | nErrId := FileClose.nErrId;
199 | nErrStep := step;
200 | step := stepDone;
201 | ELSIF NOT(FileClose.bBusy) THEN
202 | step := stepDone;
203 | END_IF
204 |
205 |
206 | stepDone:
207 | bBusy := FALSE;
208 | END_CASE
209 |
210 | IF NOT bExecute THEN
211 | step := stepReady;
212 | bBusy := FALSE;
213 | END_IF
214 | ]]>
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/Csv/MatrixCsvWriter.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
48 |
49 | 0 AND cbHeaderLen > 0 THEN
93 | step := stepWriteHeader;
94 | FileWrite.pWriteBuff := pHeader;
95 | FileWrite.cbWriteLen := cbHeaderLen;
96 | ELSE
97 | step := stepFillBuffer;
98 | END_IF;
99 | END_IF
100 |
101 | stepWriteHeader:
102 | IF FileWrite.bError THEN
103 | bError := TRUE;
104 | nErrId := FileWrite.nErrId;
105 | nErrStep := step;
106 | step := stepCloseFile;
107 | ELSIF NOT(FileWrite.bBusy) THEN
108 | step := stepFillBuffer;
109 | END_IF
110 |
111 |
112 | stepFillBuffer:
113 | //add field divider manually at the beginning of the write block
114 | IF Ci > 0 THEN
115 | buffer[0] := DEFAULT_CSV_FIELD_SEP;
116 | bufferOffset := 1;
117 | ELSE
118 | bufferOffset := 0;
119 | END_IF
120 |
121 | BuffCmd := E_EnumCmdType.eEnumCmd_First;
122 | REPEAT
123 | CsvWrite(eCmd := BuffCmd,
124 | putValue := LREAL_TO_STRING(M.GetRC(Ri,Ci)),
125 | bCRLF := M.Cols = Ci+1,
126 | pBuffer := ADR(buffer)+bufferOffset,
127 | cbBuffer := bufferSize-bufferOffset);
128 |
129 | IF NOT(CsvWrite.bOk) THEN
130 | bError := TRUE;
131 | nErrId := 1;
132 | nErrStep := step;
133 | step := stepCloseFile;
134 | RETURN;
135 | END_IF
136 |
137 | BuffCmd := E_EnumCmdType.eEnumCmd_Next;
138 | Ci := Ci + 1;
139 | IF Ci >= M.Cols THEN
140 | Ci := 0;
141 | Ri := Ri + 1;
142 | END_IF
143 | UNTIL
144 | Ri >= M.Rows OR CsvWrite.cbFree < dataSize
145 | END_REPEAT
146 | step := stepWriteBuffer;
147 | FileWrite.pWriteBuff := ADR(buffer);
148 | FileWrite.cbWriteLen := CsvWrite.cbSize+bufferOffset;
149 |
150 |
151 | stepWriteBuffer:
152 |
153 | IF FileWrite.bError THEN
154 | bError := TRUE;
155 | nErrId := FileWrite.nErrId;
156 | nErrStep := step;
157 | step := stepDone;
158 | ELSIF NOT(FileWrite.bBusy) THEN
159 | IF Ri >= M.Rows THEN
160 | step := stepCloseFile;
161 | ELSE
162 | step := stepFillBuffer;
163 | END_IF
164 | END_IF
165 |
166 | stepCloseFile:
167 |
168 | IF FileClose.bError AND NOT bError THEN
169 | bError := TRUE;
170 | nErrId := FileClose.nErrId;
171 | nErrStep := step;
172 | step := stepDone;
173 | ELSIF NOT(FileClose.bBusy) THEN
174 | step := stepDone;
175 | END_IF
176 |
177 |
178 | stepDone:
179 | bBusy := FALSE;
180 | END_CASE
181 |
182 | IF NOT bExecute THEN
183 | step := stepReady;
184 | bBusy := FALSE;
185 | END_IF
186 | ]]>
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/ExternalStaticMatrix.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
32 |
33 | = Length THEN
37 | GetI := 0.0;
38 | LogWarning('%s: Attempted I access of out-of-bounds Matrix data');
39 | ELSE
40 | GetI := Data[I];
41 | END_IF]]>
42 |
43 |
44 |
45 |
52 |
53 |
55 |
56 |
57 |
58 |
66 |
67 | = Length THEN
71 | SetI := FALSE;
72 | LogWarning('%s: Attempt to set data using I access when I is out of bounds');
73 | ELSE
74 | SetI := TRUE;
75 | Data[I] := Val;
76 | END_IF]]>
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/Functions/Arrays/Array2D_Cols.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/Functions/Arrays/Array2D_Rows.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/Functions/Arrays/Array2D_To_Matrix.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/Functions/Arrays/Matrix_SameSizeAs_Array2D.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/Functions/Arrays/Matrix_To_Array2D.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/Functions/Matrix/Matrix_CanMult.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/Functions/Matrix/Matrix_Copy.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/Functions/Matrix/Matrix_DeterminateSquare.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
18 |
19 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/Functions/Matrix/Matrix_ElementDifference.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/Functions/Matrix/Matrix_ElementProduct.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
17 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/Functions/Matrix/Matrix_ElementSum.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
17 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/Functions/Matrix/Matrix_Grow.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
25 |
26 | M_To.Rows-1 THEN
27 | Matrix_Grow := FALSE;
28 | RETURN;
29 | END_IF
30 | IF M_From.Cols <> M_To.Cols-1 THEN
31 | Matrix_Grow := FALSE;
32 | RETURN;
33 | END_IF
34 |
35 | IF Row < 0 OR Row > M_From.Rows THEN
36 | Matrix_Grow := FALSE;
37 | RETURN;
38 | END_IF
39 |
40 | IF Col < 0 OR Col > M_From.Cols THEN
41 | Matrix_Grow := FALSE;
42 | RETURN;
43 | END_IF
44 |
45 | Matrix_Grow := TRUE;
46 |
47 | //loop backwards to avoid possible overwriting the input if the same matrix is both inputs.
48 | //in order to ensure the final decrement breaks the loop condition the final valid value must be 1, not zero. So just offset all indexes by 1...
49 | FOR Ri := 0 TO M_To.Rows-1 DO
50 | FOR Ci := 0 TO M_To.Cols-1 DO
51 | IF Ri = Row AND Ci = Col THEN
52 | M_To.SetRC(Ri,Ci,DiagVal);
53 | ELSIF Ri = Row THEN
54 | M_To.SetRC(Ri,Ci,RowVal);
55 | ELSIF Ci = Col THEN
56 | M_To.SetRC(Ri,Ci,ColVal);
57 | ELSE
58 | //note that if Ri or Ci is their lowest value (1), then the BOOL condition must be false because 0 cannot be greater than any UINT.
59 | //This guarantees that the lowest RC indexes are zero.
60 | M_To.SetRC(Ri,Ci,M_From.GetRC(Ri - BOOL_TO_UINT((Ri)>Row),Ci - BOOL_TO_UINT((Ci)>Col)));
61 | END_IF
62 | END_FOR
63 | END_FOR
64 | ]]>
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/Functions/Matrix/Matrix_InvertSquare.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
19 |
20 | Mi THEN
42 | FOR Ci := 0 TO M.Cols-1 DO
43 | IF Ci <> Mi THEN
44 | M.SetRC(Ri,Ci,M.GetRC(Ri,Ci) - M.GetRC(Ri,Mi)*M.GetRC(Mi,Ci)/temp);
45 | END_IF
46 | END_FOR
47 | END_IF;
48 | END_FOR
49 |
50 | temp := -1/temp;
51 | M.SetRC(Mi,Mi,temp);
52 | FOR Ni := 0 TO M.Cols-1 DO
53 | IF Ni <> Mi THEN
54 | M.SetRC(Mi,Ni,M.GetRC(Mi,Ni)*temp);
55 | M.SetRC(Ni,Mi,M.GetRC(Ni,Mi)*temp);
56 | END_IF;
57 | END_FOR
58 |
59 | END_FOR
60 |
61 | M.Scale(-1);
62 | ]]>
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/Functions/Matrix/Matrix_Product.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
19 |
20 | Res.Rows OR B.Cols <> Res.Cols THEN
26 | Matrix_Product := FALSE;
27 | RETURN;
28 | END_IF
29 |
30 | Matrix_Product := TRUE;
31 |
32 | FOR Ri := 0 TO Res.Rows-1 DO
33 | FOR Ci := 0 TO Res.Cols-1 DO
34 | Sum := 0;
35 | FOR I := 0 TO A.Cols-1 DO
36 | Sum := Sum + A.GetRC(Ri,I) * B.GetRC(I,Ci);
37 | END_FOR
38 | Res.SetRC(Ri,Ci,Sum);
39 | END_FOR
40 | END_FOR]]>
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/Functions/Matrix/Matrix_Scale.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
17 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/Functions/Matrix/Matrix_Shrink.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
22 |
23 | MAX(1,M_From.Rows-1) OR M_To.Cols <> MAX(1,M_From.Cols-1) THEN
29 | Matrix_Shrink := FALSE;
30 | RETURN;
31 | END_IF
32 |
33 | IF Row >= M_From.Rows OR Col >= M_From.Cols THEN
34 | Matrix_Shrink := FALSE;
35 | RETURN;
36 | END_IF
37 |
38 | Matrix_Shrink := TRUE;
39 |
40 | FOR Ri := 0 TO M_To.Rows-1 DO
41 | FOR Ci := 0 TO M_To.Cols-1 DO
42 | M_To.SetRC(Ri,Ci,M_From.GetRC(Ri + BOOL_TO_UINT(Ri >= Row AND M_From.Rows <> M_To.Rows),Ci + BOOL_TO_UINT(Ci >= Col AND M_From.Cols <> M_To.Cols)));
43 | END_FOR
44 | END_FOR]]>
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/Functions/Matrix/Matrix_SubMatrix.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
24 |
25 | M_Super.Rows OR ColStart + ColCount > M_Super.Cols THEN
26 | Matrix_SubMatrix := FALSE;
27 | RETURN;
28 | END_IF
29 | IF M_Sub.Rows <> RowCount OR M_Sub.Cols <> ColCount THEN
30 | Matrix_SubMatrix := FALSE;
31 | RETURN;
32 | END_IF
33 |
34 | Matrix_SubMatrix := TRUE;
35 |
36 | IF RowCount = 0 OR ColCount = 0 THEN
37 | RETURN;//valid to get a zero-len matrix as the result, but indexing below will cause a pagefault due to creating 32k+ warning messages for invalid access
38 | END_IF
39 |
40 | FOR Ri := 0 TO RowCount-1 DO
41 | FOR Ci := 0 TO ColCount-1 DO
42 | M_Sub.SetRC(Ri,Ci,M_Super.GetRC(RowStart+Ri,ColStart+Ci));
43 | END_FOR
44 | END_FOR]]>
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/Functions/Matrix/Matrix_Transpose.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
17 | M_To.Cols OR M_From.Cols <> M_to.Rows THEN
18 | Matrix_Transpose := FALSE;
19 | RETURN;
20 | END_IF
21 |
22 | Matrix_Transpose := TRUE;
23 |
24 | FOR Ri := 0 TO M_From.Rows-1 DO
25 | FOR Ci := 0 TO M_From.Cols-1 DO
26 | M_To.SetRC(Ci,Ri,M_From.GetRC(Ri,Ci));
27 | END_FOR
28 | END_FOR]]>
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/Functions/Matrix/Matrix_TransposeSquare.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
14 |
15 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/Functions/Vector/Vector_CrossProduct.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
22 |
23 | Res.Length - 1 THEN
27 | Vector_CrossProduct := FALSE;
28 | RETURN;
29 | END_IF
30 |
31 | FOR I := LOWER_BOUND(Vectors,1) TO UPPER_BOUND(Vectors,1) DO
32 | IF Vectors[I] = 0 THEN
33 | Vector_CrossProduct := FALSE;
34 | RETURN;
35 | END_IF
36 | IF NOT(Vectors[I]^.IsVector) OR Vectors[I]^.Length <> Res.Length THEN
37 | Vector_CrossProduct := FALSE;
38 | RETURN;
39 | END_IF
40 | END_FOR
41 |
42 |
43 | IF NOT(M_Vectors.Init(Res.Length,Res.Length)) THEN
44 | Vector_CrossProduct := FALSE;
45 | RETURN;
46 | END_IF
47 |
48 |
49 | //build aggregate matrix
50 | FOR Ri := 0 TO M_Vectors.Rows-1 DO
51 | FOR Ci := 0 TO M_Vectors.Cols-1 DO
52 | IF Ri = 0 THEN
53 | M_Vectors.SetRC(Ri,Ci,1);
54 | ELSE
55 | I := LOWER_BOUND(Vectors,1)-1 + Ri;
56 | M_Vectors.SetRC(Ri,Ci,Vectors[I]^.GetI(Ci));
57 | END_IF
58 | END_FOR
59 | END_FOR
60 |
61 | //if some vectors are parallel or whatever there is no 'one' cross product, so return false
62 | IF M_Vectors.GetDeterminant() = 0 THEN
63 | Vector_CrossProduct := FALSE;
64 | RETURN;
65 | END_IF
66 |
67 | Vector_CrossProduct := TRUE;
68 |
69 | //take determiantes
70 | FOR Ci := 0 TO M_Vectors.Cols-1 DO
71 | M_Det.Init(M_Vectors,0,Ci);
72 | IF NOT(Matrix_DeterminateSquare(M_Det, Res=>Det)) THEN
73 | Vector_CrossProduct := FALSE;
74 | RETURN;
75 | END_IF
76 | Sign := ((UINT_TO_INT(Ci)+1) MOD 2)*2 -1;//even columns are positive, odd columns are negative
77 | Res.SetI(Ci,Det*Sign);
78 | END_FOR
79 |
80 | ]]>
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/Functions/Vector/Vector_DotProduct.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 | B.Length OR A.IsEmpty THEN
19 | Vector_DotProduct := FALSE;
20 | Res := 0;
21 | RETURN;
22 | END_IF
23 |
24 | Vector_DotProduct := TRUE;
25 |
26 | Sum := 0;
27 | FOR I := 0 TO A.Length-1 DO
28 | Sum := Sum + A.GetI(I)*B.GetI(I);
29 | END_FOR
30 | Res := SUM;]]>
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/Functions/Vector/Vector_Magnitude.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
17 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/Functions/Vector/Vector_Normalize.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
17 | Res.Length THEN
18 | Vector_Normalize := FALSE;
19 | RETURN;
20 | END_IF
21 |
22 | IF NOT(Vector_Magnitude(In,Res=>Mag)) THEN
23 | Vector_Normalize := FALSE;
24 | RETURN;
25 | END_IF
26 |
27 | //dont use copy because vectors might be in different orientations
28 | FOR I:= 0 TO Res.Length-1 DO
29 | Res.SetI(I,In.GetI(I)*Mag);
30 | END_FOR]]>
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/MatrixAccessors/MatrixAccessor.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
31 |
32 | = Length THEN
39 | GetI := 0.0;
40 | LogWarning('%s: Attempted I access beyond limits of Matrix Accessor');
41 | ELSE
42 | GetI := M_.GetI(This2Parent(I));
43 | END_IF]]>
44 |
45 |
46 |
47 |
52 |
53 |
54 |
55 |
56 |
57 |
65 |
66 | = Length THEN
73 | SetI := FALSE;
74 | LogWarning('%s: Attempted I access beyond limits of Matrix Accessor');
75 | ELSE
76 | SetI := M_.SetI(This2Parent(I),Val);
77 | END_IF]]>
78 |
79 |
80 |
81 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/MatrixAccessors/ShrunkMatrixAccessor.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
22 |
23 |
26 |
27 | 0 THEN
31 | Cols := M_.Cols-1;
32 | ELSE
33 | Cols := 0;
34 | END_IF]]>
35 |
36 |
37 |
38 |
39 |
46 |
47 |
50 |
51 |
52 |
53 |
55 |
56 |
59 |
60 | 0 THEN
64 | Rows := M_.Rows-1;
65 | ELSE
66 | Rows := 0;
67 | END_IF]]>
68 |
69 |
70 |
71 |
72 |
81 |
82 | ThisR, Col => ThisC);
89 |
90 | This2Parent := RCC2I(ThisR+BOOL_TO_UINT(RowRemoved_<=ThisR),ThisC+BOOL_TO_UINT(ColRemoved_<=ThisC),M_.Cols);]]>
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/MatrixAccessors/SubMatrixAccessor.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
24 |
25 |
28 |
29 | M_.Cols THEN
33 | Cols := 0;
34 | ELSE
35 | Cols := ColCount_;
36 | END_IF]]>
37 |
38 |
39 |
40 |
41 |
50 |
51 |
56 |
57 |
58 |
59 |
61 |
62 |
65 |
66 | M_.Rows THEN
70 | Rows := 0;
71 | ELSE
72 | Rows := RowCount_;
73 | END_IF]]>
74 |
75 |
76 |
77 |
78 |
87 |
88 | ThisR, Col => ThisC);
95 | This2Parent := RCC2I(ThisR+RowStart_,ThisC+ColStart_,M_.Cols);]]>
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/MatrixAccessors/TransposeMatrixAccessor.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
22 |
23 |
26 |
27 |
33 |
34 |
35 |
36 |
37 |
42 |
43 |
44 |
45 |
46 |
47 |
49 |
50 |
53 |
54 |
60 |
61 |
62 |
63 |
64 |
73 |
74 | ThisR, Col => ThisC);
81 |
82 | This2Parent := RCC2I(ThisC,ThisR,M_.Cols);]]>
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/POUs/StaticMatrix.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
29 |
30 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
45 |
46 |
48 |
49 |
50 |
51 |
53 |
54 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/TcMatrix.plcproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | 1.0.0.0
4 | 2.0
5 | {c0f4bef7-55d3-4b7e-a92a-8580425ecfb1}
6 | True
7 | true
8 | true
9 | false
10 | TcMatrix
11 | 3.1.4023.0
12 | {8ec408c3-a544-4a75-9918-b9e0bcde03c0}
13 | {a002c4ff-eb8a-4723-9b5c-4867c37c6d11}
14 | {55280038-9b8d-402f-b14c-4fb127dddb5c}
15 | {bbd717dd-a9af-4f58-9010-62c8b0afd061}
16 | {0530cbe7-771f-4e48-bb43-655369b89363}
17 | {696e4867-e7af-4d84-8e99-6d19d1fc0070}
18 | Burks Engineering
19 | false
20 | TcMatrix
21 | 1.4.3
22 | TcMatrix
23 | Andrew Burks
24 | Matrix arithmatic library
25 | true
26 | true
27 | reStructuredText
28 |
29 |
30 | {d5875a41-817d-44f3-8af7-6c59eaddc95f}
31 | 1.0.0.0
32 | Burks
33 |
34 |
35 | {426a88ee-bb19-4918-8554-e1c9c24621f9}
36 | 1.0.0.0
37 |
38 | {d5875a41-817d-44f3-8af7-6c59eaddc95f}
39 |
40 | Matrix
41 |
42 |
43 |
44 | {426a88ee-bb19-4918-8554-e1c9c24621f9}
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | Code
60 |
61 |
62 | Code
63 |
64 |
65 | Code
66 |
67 |
68 | Code
69 |
70 |
71 | Code
72 |
73 |
74 | Code
75 |
76 |
77 | Code
78 |
79 |
80 | Code
81 |
82 |
83 | Code
84 |
85 |
86 | Code
87 |
88 |
89 | Code
90 |
91 |
92 | Code
93 |
94 |
95 | Code
96 |
97 |
98 | Code
99 |
100 |
101 | Code
102 |
103 |
104 | Code
105 |
106 |
107 | Code
108 |
109 |
110 | Code
111 |
112 |
113 | Code
114 |
115 |
116 | Code
117 |
118 |
119 | Code
120 |
121 |
122 | Code
123 |
124 |
125 | Code
126 |
127 |
128 | Code
129 |
130 |
131 | Code
132 |
133 |
134 | Code
135 |
136 |
137 | Code
138 |
139 |
140 | Code
141 |
142 |
143 | Code
144 |
145 |
146 | Code
147 |
148 |
149 | Code
150 |
151 |
152 | Code
153 |
154 |
155 | Code
156 |
157 |
158 | Code
159 |
160 |
161 | Code
162 |
163 |
164 |
165 |
166 | Tc2_Standard, * (Beckhoff Automation GmbH)
167 | Tc2_Standard
168 |
169 |
170 | Tc2_System, * (Beckhoff Automation GmbH)
171 | Tc2_System
172 |
173 |
174 | Tc2_Utilities, * (Beckhoff Automation GmbH)
175 | Tc2_Utilities
176 |
177 |
178 | Tc3_DynamicMemory, * (Beckhoff Automation GmbH)
179 | Tc3_DynamicMemory
180 |
181 |
182 |
183 |
184 | Content
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 | "<ProjectRoot>"
193 |
194 | {192FAD59-8248-4824-A8DE-9177C94C195A}
195 |
196 | "{192FAD59-8248-4824-A8DE-9177C94C195A}"
197 |
198 |
199 |
200 | {29BD8D0C-3586-4548-BB48-497B9A01693F}
201 |
202 | "{29BD8D0C-3586-4548-BB48-497B9A01693F}"
203 |
204 | Rules
205 |
206 | "Rules"
207 |
208 |
209 |
210 |
211 |
212 |
213 | {40450F57-0AA3-4216-96F3-5444ECB29763}
214 |
215 | "{40450F57-0AA3-4216-96F3-5444ECB29763}"
216 |
217 |
218 | ActiveVisuProfile
219 | IR0whWr8bwfwBwAAiD2qpQAAAABVAgAA37x72QAAAAABAAAAAAAAAAEaUwB5AHMAdABlAG0ALgBTAHQAcgBpAG4AZwACTHsAZgA5ADUAYgBiADQAMgA2AC0ANQA1ADIANAAtADQAYgA0ADUALQA5ADQAMAAwAC0AZgBiADAAZgAyAGUANwA3AGUANQAxAGIAfQADCE4AYQBtAGUABDBUAHcAaQBuAEMAQQBUACAAMwAuADEAIABCAHUAaQBsAGQAIAA0ADAAMgA0AC4ANwAFFlAAcgBvAGYAaQBsAGUARABhAHQAYQAGTHsAMQA2AGUANQA1AGIANgAwAC0ANwAwADQAMwAtADQAYQA2ADMALQBiADYANQBiAC0ANgAxADQANwAxADMAOAA3ADgAZAA0ADIAfQAHEkwAaQBiAHIAYQByAGkAZQBzAAhMewAzAGIAZgBkADUANAA1ADkALQBiADAANwBmAC0ANABkADYAZQAtAGEAZQAxAGEALQBhADgAMwAzADUANgBhADUANQAxADQAMgB9AAlMewA5AGMAOQA1ADgAOQA2ADgALQAyAGMAOAA1AC0ANAAxAGIAYgAtADgAOAA3ADEALQA4ADkANQBmAGYAMQBmAGUAZABlADEAYQB9AAoOVgBlAHIAcwBpAG8AbgALBmkAbgB0AAwKVQBzAGEAZwBlAA0KVABpAHQAbABlAA4aVgBpAHMAdQBFAGwAZQBtAE0AZQB0AGUAcgAPDkMAbwBtAHAAYQBuAHkAEAxTAHkAcwB0AGUAbQARElYAaQBzAHUARQBsAGUAbQBzABIwVgBpAHMAdQBFAGwAZQBtAHMAUwBwAGUAYwBpAGEAbABDAG8AbgB0AHIAbwBsAHMAEyhWAGkAcwB1AEUAbABlAG0AcwBXAGkAbgBDAG8AbgB0AHIAbwBsAHMAFCRWAGkAcwB1AEUAbABlAG0AVABlAHgAdABFAGQAaQB0AG8AcgAVIlYAaQBzAHUATgBhAHQAaQB2AGUAQwBvAG4AdAByAG8AbAAWFHYAaQBzAHUAaQBuAHAAdQB0AHMAFwxzAHkAcwB0AGUAbQAYGFYAaQBzAHUARQBsAGUAbQBCAGEAcwBlABkmRABlAHYAUABsAGEAYwBlAGgAbwBsAGQAZQByAHMAVQBzAGUAZAAaCGIAbwBvAGwAGyJQAGwAdQBnAGkAbgBDAG8AbgBzAHQAcgBhAGkAbgB0AHMAHEx7ADQAMwBkADUAMgBiAGMAZQAtADkANAAyAGMALQA0ADQAZAA3AC0AOQBlADkANAAtADEAYgBmAGQAZgAzADEAMABlADYAMwBjAH0AHRxBAHQATABlAGEAcwB0AFYAZQByAHMAaQBvAG4AHhRQAGwAdQBnAGkAbgBHAHUAaQBkAB8WUwB5AHMAdABlAG0ALgBHAHUAaQBkACBIYQBmAGMAZAA1ADQANAA2AC0ANAA5ADEANAAtADQAZgBlADcALQBiAGIANwA4AC0AOQBiAGYAZgBlAGIANwAwAGYAZAAxADcAIRRVAHAAZABhAHQAZQBJAG4AZgBvACJMewBiADAAMwAzADYANgBhADgALQBiADUAYwAwAC0ANABiADkAYQAtAGEAMAAwAGUALQBlAGIAOAA2ADAAMQAxADEAMAA0AGMAMwB9ACMOVQBwAGQAYQB0AGUAcwAkTHsAMQA4ADYAOABmAGYAYwA5AC0AZQA0AGYAYwAtADQANQAzADIALQBhAGMAMAA2AC0AMQBlADMAOQBiAGIANQA1ADcAYgA2ADkAfQAlTHsAYQA1AGIAZAA0ADgAYwAzAC0AMABkADEANwAtADQAMQBiADUALQBiADEANgA0AC0ANQBmAGMANgBhAGQAMgBiADkANgBiADcAfQAmFk8AYgBqAGUAYwB0AHMAVAB5AHAAZQAnVFUAcABkAGEAdABlAEwAYQBuAGcAdQBhAGcAZQBNAG8AZABlAGwARgBvAHIAQwBvAG4AdgBlAHIAdABpAGIAbABlAEwAaQBiAHIAYQByAGkAZQBzACgQTABpAGIAVABpAHQAbABlACkUTABpAGIAQwBvAG0AcABhAG4AeQAqHlUAcABkAGEAdABlAFAAcgBvAHYAaQBkAGUAcgBzACs4UwB5AHMAdABlAG0ALgBDAG8AbABsAGUAYwB0AGkAbwBuAHMALgBIAGEAcwBoAHQAYQBiAGwAZQAsEnYAaQBzAHUAZQBsAGUAbQBzAC1INgBjAGIAMQBjAGQAZQAxAC0AZAA1AGQAYwAtADQAYQAzAGIALQA5ADAANQA0AC0AMgAxAGYAYQA3ADUANgBhADMAZgBhADQALihJAG4AdABlAHIAZgBhAGMAZQBWAGUAcgBzAGkAbwBuAEkAbgBmAG8AL0x7AGMANgAxADEAZQA0ADAAMAAtADcAZgBiADkALQA0AGMAMwA1AC0AYgA5AGEAYwAtADQAZQAzADEANABiADUAOQA5ADYANAAzAH0AMBhNAGEAagBvAHIAVgBlAHIAcwBpAG8AbgAxGE0AaQBuAG8AcgBWAGUAcgBzAGkAbwBuADIMTABlAGcAYQBjAHkAMzBMAGEAbgBnAHUAYQBnAGUATQBvAGQAZQBsAFYAZQByAHMAaQBvAG4ASQBuAGYAbwA0MEwAbwBhAGQATABpAGIAcgBhAHIAaQBlAHMASQBuAHQAbwBQAHIAbwBqAGUAYwB0ADUaQwBvAG0AcABhAHQAaQBiAGkAbABpAHQAeQDQAAIaA9ADAS0E0AUGGgfQBwgaAUUHCQjQAAkaBEUKCwQDAAAABQAAAA0AAAAAAAAA0AwLrQIAAADQDQEtDtAPAS0Q0AAJGgRFCgsEAwAAAAUAAAANAAAAKAAAANAMC60BAAAA0A0BLRHQDwEtENAACRoERQoLBAMAAAAFAAAADQAAAAAAAADQDAutAgAAANANAS0S0A8BLRDQAAkaBEUKCwQDAAAABQAAAA0AAAAUAAAA0AwLrQIAAADQDQEtE9APAS0Q0AAJGgRFCgsEAwAAAAUAAAANAAAAAAAAANAMC60CAAAA0A0BLRTQDwEtENAACRoERQoLBAMAAAAFAAAADQAAAAAAAADQDAutAgAAANANAS0V0A8BLRDQAAkaBEUKCwQDAAAABQAAAA0AAAAAAAAA0AwLrQIAAADQDQEtFtAPAS0X0AAJGgRFCgsEAwAAAAUAAAANAAAAKAAAANAMC60EAAAA0A0BLRjQDwEtENAZGq0BRRscAdAAHBoCRR0LBAMAAAAFAAAADQAAAAAAAADQHh8tINAhIhoCRSMkAtAAJRoFRQoLBAMAAAADAAAAAAAAAAoAAADQJgutAAAAANADAS0n0CgBLRHQKQEtENAAJRoFRQoLBAMAAAADAAAAAAAAAAoAAADQJgutAQAAANADAS0n0CgBLRHQKQEtEJoqKwFFAAEC0AABLSzQAAEtF9AAHy0t0C4vGgPQMAutAQAAANAxC60XAAAA0DIarQDQMy8aA9AwC60CAAAA0DELrQMAAADQMhqtANA0Gq0A0DUarQA=
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 | System.Collections.Hashtable
228 | {54dd0eac-a6d8-46f2-8c27-2f43c7e49861}
229 | System.String
230 |
231 |
232 |
233 |
234 |
--------------------------------------------------------------------------------
/TcMatrix/TcMatrix/Version/Global_Version.TcGVL:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 |
14 |
--------------------------------------------------------------------------------
/TcMatrixTest/TcMatrixTest.tsproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | PlcTask
11 |
12 |
13 |
14 |
15 |
16 |
17 | TcMatrixTest Instance
18 | {08500001-0000-0000-F000-000000000064}
19 |
20 |
21 | 0
22 | PlcTask
23 |
24 | #x02010030
25 |
26 | 20
27 | 10000000
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/TcMatrixTest/TcMatrixTest/PlcTask.TcTTO:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 10000
6 | 20
7 |
8 | PRG_TEST
9 |
10 | {9b75a233-b2fa-4356-b033-b3a5400daf73}
11 | {6076d168-c44a-407b-aeea-77de7f1456ee}
12 | {2a2da5c4-7b4e-4691-9c70-8a2799caae79}
13 | {8d1d71c3-4d2f-47ab-827c-37893fb4fe4d}
14 | {8f2a9d96-a8d2-4504-801c-5af985aa447a}
15 |
16 |
--------------------------------------------------------------------------------
/TcMatrixTest/TcMatrixTest/TESTs/FB_Array_Test.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
16 |
17 |
18 |
35 |
36 |
59 |
60 |
61 |
62 |
80 |
81 |
111 |
112 |
113 |
114 |
130 |
131 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
--------------------------------------------------------------------------------
/TcMatrixTest/TcMatrixTest/TESTs/FB_CsvReadWrite_Test.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
14 |
15 |
16 |
37 |
38 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/TcMatrixTest/TcMatrixTest/TESTs/FB_DynamicMatrix_Test.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
17 |
18 |
19 |
20 |
29 |
30 |
43 |
44 |
45 |
46 |
55 |
56 |
71 |
72 |
73 |
74 |
83 |
84 |
98 |
99 |
100 |
101 |
110 |
111 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
--------------------------------------------------------------------------------
/TcMatrixTest/TcMatrixTest/TESTs/FB_MatrixDeterminate_Test.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
15 |
16 |
17 |
26 |
27 | Actual);
32 |
33 | // @TEST-ASSERT
34 | AssertTrue(Result,'Main function call was not successful');
35 | AssertEquals(Expected,Actual,'Determinate value was incorrect');
36 |
37 | TEST_FINISHED();]]>
38 |
39 |
40 |
41 |
50 |
51 | Actual);
56 |
57 | // @TEST-ASSERT
58 | AssertFalse(Result,'Main function call was unexpectedly successful');
59 | AssertEquals(Expected,Actual,'Determinate value was incorrect');
60 |
61 | TEST_FINISHED();]]>
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/TcMatrixTest/TcMatrixTest/TESTs/FB_MatrixElementProduct_Test.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
15 |
16 |
17 |
26 |
27 |
38 |
39 |
40 |
41 |
50 |
51 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/TcMatrixTest/TcMatrixTest/TESTs/FB_MatrixElementSum_Test.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
15 |
16 |
17 |
26 |
27 |
38 |
39 |
40 |
41 |
50 |
51 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/TcMatrixTest/TcMatrixTest/TESTs/FB_MatrixGetMagicSquare_Test.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
14 |
15 |
16 |
26 |
27 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/TcMatrixTest/TcMatrixTest/TESTs/FB_MatrixGrow_Test.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
16 |
17 |
18 |
26 |
27 |
37 |
38 |
39 |
40 |
49 |
50 |
62 |
63 |
64 |
65 |
73 |
74 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
--------------------------------------------------------------------------------
/TcMatrixTest/TcMatrixTest/TESTs/FB_MatrixInvert_Test.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
17 |
18 |
19 |
27 |
28 |
40 |
41 |
42 |
43 |
51 |
52 |
62 |
63 |
64 |
65 |
75 |
76 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
--------------------------------------------------------------------------------
/TcMatrixTest/TcMatrixTest/TESTs/FB_MatrixMatrixProduct_Test.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
17 |
18 |
19 |
28 |
29 |
40 |
41 |
42 |
43 |
52 |
53 |
67 |
68 |
69 |
70 |
79 |
80 |
94 |
95 |
96 |
97 |
106 |
107 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
--------------------------------------------------------------------------------
/TcMatrixTest/TcMatrixTest/TESTs/FB_MatrixShrink_Test.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
15 |
16 |
17 |
25 |
26 |
36 |
37 |
38 |
39 |
48 |
49 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/TcMatrixTest/TcMatrixTest/TESTs/FB_MatrixSubMatrix_Test.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 |
14 |
15 |
16 |
17 |
31 |
32 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/TcMatrixTest/TcMatrixTest/TESTs/FB_MatrixTranspose_Test.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
16 |
17 |
18 |
27 |
28 |
41 |
42 |
43 |
44 |
53 |
54 |
67 |
68 |
69 |
70 |
82 |
83 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
--------------------------------------------------------------------------------
/TcMatrixTest/TcMatrixTest/TESTs/FB_StaticMatrix_Test.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
14 |
15 |
16 |
26 |
27 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/TcMatrixTest/TcMatrixTest/TESTs/FB_VectorCrossProduct_Test.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
16 |
17 |
18 |
30 |
31 |
50 |
51 |
52 |
53 |
65 |
66 |
84 |
85 |
86 |
87 |
97 |
98 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
--------------------------------------------------------------------------------
/TcMatrixTest/TcMatrixTest/TESTs/PRG_TEST.TcPOU:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/TcMatrixTest/TcMatrixTest/TcMatrixTest.plcproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | 1.0.0.0
4 | 2.0
5 | {d894bf7b-783c-4a82-8af1-3d395565c311}
6 | True
7 | true
8 | true
9 | false
10 | TcMatrixTest
11 | 3.1.4023.0
12 | {7e72f38d-c49a-4167-a7df-3d3d3c1a22d3}
13 | {a9df0001-c2d5-4050-8f34-930bd6c91f07}
14 | {e8f56aa0-def9-4aea-8fa5-31071a156ee5}
15 | {7b9b3f09-514f-456f-9be3-5742f173d1ff}
16 | {79cc4822-ca77-4885-a1fc-84c408e29968}
17 | {fcb5c87e-e41c-422e-9ee7-2814e0fa659f}
18 | Burks Engineering
19 | false
20 | TcMatrix Unit Tests
21 | 0.0.0
22 | true
23 | true
24 | Andrew Burks
25 | Unit Tests for the TcMatrix Library
26 |
27 |
28 |
29 | Code
30 |
31 |
32 | Code
33 |
34 |
35 | Code
36 |
37 |
38 | Code
39 |
40 |
41 | Code
42 |
43 |
44 | Code
45 |
46 |
47 | Code
48 |
49 |
50 | Code
51 |
52 |
53 | Code
54 |
55 |
56 | Code
57 |
58 |
59 | Code
60 |
61 |
62 | Code
63 |
64 |
65 | Code
66 |
67 |
68 | Code
69 |
70 |
71 | Code
72 |
73 |
74 | Code
75 |
76 |
77 | Code
78 |
79 |
80 | Code
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 | Tc2_Standard, * (Beckhoff Automation GmbH)
91 | Tc2_Standard
92 |
93 |
94 | Tc2_System, * (Beckhoff Automation GmbH)
95 | Tc2_System
96 |
97 |
98 | Tc3_DynamicMemory, * (Beckhoff Automation GmbH)
99 | Tc3_DynamicMemory
100 |
101 |
102 | Tc3_Module, * (Beckhoff Automation GmbH)
103 | Tc3_Module
104 |
105 |
106 | TcMatrix, * (Burks Engineering)
107 | TcMatrix
108 |
109 |
110 |
111 |
112 | TcUnit
113 |
114 |
115 |
116 |
117 | Content
118 |
119 |
120 |
121 |
122 | TcMatrix, * (Burks Engineering)
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 | "<ProjectRoot>"
131 |
132 | {192FAD59-8248-4824-A8DE-9177C94C195A}
133 |
134 | "{192FAD59-8248-4824-A8DE-9177C94C195A}"
135 |
136 |
137 |
138 | {29BD8D0C-3586-4548-BB48-497B9A01693F}
139 |
140 | "{29BD8D0C-3586-4548-BB48-497B9A01693F}"
141 |
142 | Rules
143 |
144 | "Rules"
145 |
146 |
147 |
148 |
149 |
150 |
151 | {8F99A816-E488-41E4-9FA3-846536012284}
152 |
153 | "{8F99A816-E488-41E4-9FA3-846536012284}"
154 |
155 |
156 | DisabledWarningIds
157 | 394
158 |
159 |
160 | {40450F57-0AA3-4216-96F3-5444ECB29763}
161 |
162 | "{40450F57-0AA3-4216-96F3-5444ECB29763}"
163 |
164 |
165 | ActiveVisuProfile
166 | IR0whWr8bwfwBwAAiD2qpQAAAABVAgAA37x72QAAAAABAAAAAAAAAAEaUwB5AHMAdABlAG0ALgBTAHQAcgBpAG4AZwACTHsAZgA5ADUAYgBiADQAMgA2AC0ANQA1ADIANAAtADQAYgA0ADUALQA5ADQAMAAwAC0AZgBiADAAZgAyAGUANwA3AGUANQAxAGIAfQADCE4AYQBtAGUABDBUAHcAaQBuAEMAQQBUACAAMwAuADEAIABCAHUAaQBsAGQAIAA0ADAAMgA0AC4ANwAFFlAAcgBvAGYAaQBsAGUARABhAHQAYQAGTHsAMQA2AGUANQA1AGIANgAwAC0ANwAwADQAMwAtADQAYQA2ADMALQBiADYANQBiAC0ANgAxADQANwAxADMAOAA3ADgAZAA0ADIAfQAHEkwAaQBiAHIAYQByAGkAZQBzAAhMewAzAGIAZgBkADUANAA1ADkALQBiADAANwBmAC0ANABkADYAZQAtAGEAZQAxAGEALQBhADgAMwAzADUANgBhADUANQAxADQAMgB9AAlMewA5AGMAOQA1ADgAOQA2ADgALQAyAGMAOAA1AC0ANAAxAGIAYgAtADgAOAA3ADEALQA4ADkANQBmAGYAMQBmAGUAZABlADEAYQB9AAoOVgBlAHIAcwBpAG8AbgALBmkAbgB0AAwKVQBzAGEAZwBlAA0KVABpAHQAbABlAA4aVgBpAHMAdQBFAGwAZQBtAE0AZQB0AGUAcgAPDkMAbwBtAHAAYQBuAHkAEAxTAHkAcwB0AGUAbQARElYAaQBzAHUARQBsAGUAbQBzABIwVgBpAHMAdQBFAGwAZQBtAHMAUwBwAGUAYwBpAGEAbABDAG8AbgB0AHIAbwBsAHMAEyhWAGkAcwB1AEUAbABlAG0AcwBXAGkAbgBDAG8AbgB0AHIAbwBsAHMAFCRWAGkAcwB1AEUAbABlAG0AVABlAHgAdABFAGQAaQB0AG8AcgAVIlYAaQBzAHUATgBhAHQAaQB2AGUAQwBvAG4AdAByAG8AbAAWFHYAaQBzAHUAaQBuAHAAdQB0AHMAFwxzAHkAcwB0AGUAbQAYGFYAaQBzAHUARQBsAGUAbQBCAGEAcwBlABkmRABlAHYAUABsAGEAYwBlAGgAbwBsAGQAZQByAHMAVQBzAGUAZAAaCGIAbwBvAGwAGyJQAGwAdQBnAGkAbgBDAG8AbgBzAHQAcgBhAGkAbgB0AHMAHEx7ADQAMwBkADUAMgBiAGMAZQAtADkANAAyAGMALQA0ADQAZAA3AC0AOQBlADkANAAtADEAYgBmAGQAZgAzADEAMABlADYAMwBjAH0AHRxBAHQATABlAGEAcwB0AFYAZQByAHMAaQBvAG4AHhRQAGwAdQBnAGkAbgBHAHUAaQBkAB8WUwB5AHMAdABlAG0ALgBHAHUAaQBkACBIYQBmAGMAZAA1ADQANAA2AC0ANAA5ADEANAAtADQAZgBlADcALQBiAGIANwA4AC0AOQBiAGYAZgBlAGIANwAwAGYAZAAxADcAIRRVAHAAZABhAHQAZQBJAG4AZgBvACJMewBiADAAMwAzADYANgBhADgALQBiADUAYwAwAC0ANABiADkAYQAtAGEAMAAwAGUALQBlAGIAOAA2ADAAMQAxADEAMAA0AGMAMwB9ACMOVQBwAGQAYQB0AGUAcwAkTHsAMQA4ADYAOABmAGYAYwA5AC0AZQA0AGYAYwAtADQANQAzADIALQBhAGMAMAA2AC0AMQBlADMAOQBiAGIANQA1ADcAYgA2ADkAfQAlTHsAYQA1AGIAZAA0ADgAYwAzAC0AMABkADEANwAtADQAMQBiADUALQBiADEANgA0AC0ANQBmAGMANgBhAGQAMgBiADkANgBiADcAfQAmFk8AYgBqAGUAYwB0AHMAVAB5AHAAZQAnVFUAcABkAGEAdABlAEwAYQBuAGcAdQBhAGcAZQBNAG8AZABlAGwARgBvAHIAQwBvAG4AdgBlAHIAdABpAGIAbABlAEwAaQBiAHIAYQByAGkAZQBzACgQTABpAGIAVABpAHQAbABlACkUTABpAGIAQwBvAG0AcABhAG4AeQAqHlUAcABkAGEAdABlAFAAcgBvAHYAaQBkAGUAcgBzACs4UwB5AHMAdABlAG0ALgBDAG8AbABsAGUAYwB0AGkAbwBuAHMALgBIAGEAcwBoAHQAYQBiAGwAZQAsEnYAaQBzAHUAZQBsAGUAbQBzAC1INgBjAGIAMQBjAGQAZQAxAC0AZAA1AGQAYwAtADQAYQAzAGIALQA5ADAANQA0AC0AMgAxAGYAYQA3ADUANgBhADMAZgBhADQALihJAG4AdABlAHIAZgBhAGMAZQBWAGUAcgBzAGkAbwBuAEkAbgBmAG8AL0x7AGMANgAxADEAZQA0ADAAMAAtADcAZgBiADkALQA0AGMAMwA1AC0AYgA5AGEAYwAtADQAZQAzADEANABiADUAOQA5ADYANAAzAH0AMBhNAGEAagBvAHIAVgBlAHIAcwBpAG8AbgAxGE0AaQBuAG8AcgBWAGUAcgBzAGkAbwBuADIMTABlAGcAYQBjAHkAMzBMAGEAbgBnAHUAYQBnAGUATQBvAGQAZQBsAFYAZQByAHMAaQBvAG4ASQBuAGYAbwA0MEwAbwBhAGQATABpAGIAcgBhAHIAaQBlAHMASQBuAHQAbwBQAHIAbwBqAGUAYwB0ADUaQwBvAG0AcABhAHQAaQBiAGkAbABpAHQAeQDQAAIaA9ADAS0E0AUGGgfQBwgaAUUHCQjQAAkaBEUKCwQDAAAABQAAAA0AAAAAAAAA0AwLrQIAAADQDQEtDtAPAS0Q0AAJGgRFCgsEAwAAAAUAAAANAAAAKAAAANAMC60BAAAA0A0BLRHQDwEtENAACRoERQoLBAMAAAAFAAAADQAAAAAAAADQDAutAgAAANANAS0S0A8BLRDQAAkaBEUKCwQDAAAABQAAAA0AAAAUAAAA0AwLrQIAAADQDQEtE9APAS0Q0AAJGgRFCgsEAwAAAAUAAAANAAAAAAAAANAMC60CAAAA0A0BLRTQDwEtENAACRoERQoLBAMAAAAFAAAADQAAAAAAAADQDAutAgAAANANAS0V0A8BLRDQAAkaBEUKCwQDAAAABQAAAA0AAAAAAAAA0AwLrQIAAADQDQEtFtAPAS0X0AAJGgRFCgsEAwAAAAUAAAANAAAAKAAAANAMC60EAAAA0A0BLRjQDwEtENAZGq0BRRscAdAAHBoCRR0LBAMAAAAFAAAADQAAAAAAAADQHh8tINAhIhoCRSMkAtAAJRoFRQoLBAMAAAADAAAAAAAAAAoAAADQJgutAAAAANADAS0n0CgBLRHQKQEtENAAJRoFRQoLBAMAAAADAAAAAAAAAAoAAADQJgutAQAAANADAS0n0CgBLRHQKQEtEJoqKwFFAAEC0AABLSzQAAEtF9AAHy0t0C4vGgPQMAutAQAAANAxC60XAAAA0DIarQDQMy8aA9AwC60CAAAA0DELrQMAAADQMhqtANA0Gq0A0DUarQA=
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 | System.Collections.Hashtable
175 | {54dd0eac-a6d8-46f2-8c27-2f43c7e49861}
176 | System.String
177 |
178 |
179 |
180 |
181 |
--------------------------------------------------------------------------------
/TcMatrixTest/TcMatrixTest/Version/Global_Version.TcGVL:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 |
14 |
--------------------------------------------------------------------------------