Update upstream source from tag 'upstream/6.7.0+ds'
Update to upstream version '6.7.0+ds'
with Debian dir fc074369cc023f6dd125d7fe728736417c7ae2f0
Timo Röhling
3 years ago
0 | # More info: | |
1 | # https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners | |
2 | ||
3 | * @scpeters | |
4 | tutorials/* @maryaB-osr |
0 | #!/bin/sh -l | |
1 | ||
2 | set -x | |
3 | ||
4 | BUILD_DIR=`pwd` | |
5 | ||
6 | # Install | |
7 | make install | |
8 | ||
9 | # Compile examples | |
10 | cd ../examples | |
11 | mkdir build | |
12 | cd build | |
13 | cmake .. | |
14 | make | |
15 | ./graph_example | |
16 | ||
17 | cd $BUILD_DIR |
0 | name: Ubuntu CI | |
1 | ||
2 | on: [push, pull_request] | |
3 | ||
4 | jobs: | |
5 | bionic-ci: | |
6 | runs-on: ubuntu-latest | |
7 | name: Ubuntu Bionic CI | |
8 | steps: | |
9 | - name: Checkout | |
10 | uses: actions/checkout@v2 | |
11 | - name: Compile and test | |
12 | id: ci | |
13 | uses: ignition-tooling/action-ignition-ci@master | |
14 | with: | |
15 | codecov-token: ${{ secrets.CODECOV_TOKEN }} | |
16 | focal-ci: | |
17 | runs-on: ubuntu-latest | |
18 | name: Ubuntu Focal CI | |
19 | steps: | |
20 | - name: Checkout | |
21 | uses: actions/checkout@v2 | |
22 | - name: Compile and test | |
23 | id: ci | |
24 | uses: ignition-tooling/action-ignition-ci@focal |
0 | name: PR Collection Labeler | |
1 | ||
2 | on: pull_request_target | |
3 | ||
4 | jobs: | |
5 | pr_collection_labeler: | |
6 | runs-on: ubuntu-latest | |
7 | steps: | |
8 | - name: Add collection labels | |
9 | if: github.event.action == 'opened' | |
10 | uses: ignition-tooling/pr-collection-labeler@v1 | |
11 | with: | |
12 | github-token: ${{ secrets.GITHUB_TOKEN }} |
0 | on: | |
1 | issues: | |
2 | types: [opened] | |
3 | pull_request_target: | |
4 | types: [opened] | |
5 | name: Ticket opened | |
6 | jobs: | |
7 | assign: | |
8 | name: Add ticket to inbox | |
9 | runs-on: ubuntu-latest | |
10 | steps: | |
11 | - name: Add ticket to inbox | |
12 | uses: technote-space/create-project-card-action@v1 | |
13 | with: | |
14 | PROJECT: Core development | |
15 | COLUMN: Inbox | |
16 | GITHUB_TOKEN: ${{ secrets.TRIAGE_TOKEN }} | |
17 | CHECK_ORG_PROJECT: true | |
18 |
2 | 2 | #============================================================================ |
3 | 3 | # Initialize the project |
4 | 4 | #============================================================================ |
5 | project(ignition-math6 VERSION 6.4.0) | |
5 | project(ignition-math6 VERSION 6.7.0) | |
6 | 6 | |
7 | 7 | #============================================================================ |
8 | 8 | # Find ignition-cmake |
0 | See the [Ignition Robotics contributing guide](https://bitbucket.org/ignitionrobotics/ign-gazebo/src/default/CONTRIBUTING.md). | |
0 | See the [Ignition Robotics contributing guide](https://ignitionrobotics.org/docs/all/contributing). |
0 | 0 | ## Ignition Math 6.x |
1 | 1 | |
2 | ### Ignition Math 6.4.0 | |
2 | ## Ignition Math 6.x.x | |
3 | ||
4 | ## Ignition Math 6.7.0 (2020-1X-XX) | |
5 | ||
6 | 1. Capsule: new shape class with inertia calculation method | |
7 | * [Pull request 163](https://github.com/ignitionrobotics/ign-math/pull/163) | |
8 | ||
9 | 1. Add missing header to Color.hh | |
10 | * [Pull request 162](https://github.com/ignitionrobotics/ign-math/pull/162) | |
11 | ||
12 | 1. Improve tests of `Vector2`, `Vector3`, `Vector4`, `Quaternion`, and `Pose3` | |
13 | * [Pull request 172](https://github.com/ignitionrobotics/ign-math/pull/172) | |
14 | * [Pull request 173](https://github.com/ignitionrobotics/ign-math/pull/173) | |
15 | * [Pull request 174](https://github.com/ignitionrobotics/ign-math/pull/174) | |
16 | * [Issue 76](https://github.com/ignitionrobotics/ign-math/issues/76) | |
17 | ||
18 | 1. Pose3: document `operator*` | |
19 | * [Pull request 170](https://github.com/ignitionrobotics/ign-math/pull/170) | |
20 | ||
21 | 1. Quaternion: add Normalized() method | |
22 | * [Pull request 169](https://github.com/ignitionrobotics/ign-math/pull/169) | |
23 | ||
24 | 1. Vector2: add Round(), Rounded() methods | |
25 | * [Pull request 166](https://github.com/ignitionrobotics/ign-math/pull/166) | |
26 | * [Issue 71](https://github.com/ignitionrobotics/ign-math/issues/71) | |
27 | ||
28 | 1. Add test for printing `inf` `Vector3` | |
29 | * [Pull request 168](https://github.com/ignitionrobotics/ign-math/pull/168) | |
30 | * [Issue 64](https://github.com/ignitionrobotics/ign-math/issues/64) | |
31 | ||
32 | ## Ignition Math 6.6.0 (2020-09-16) | |
33 | ||
34 | 1. Add chrono duration helper functions | |
35 | * [Pull request 158](https://github.com/ignitionrobotics/ign-math/pull/158) | |
36 | ||
37 | ## Ignition Math 6.5.0 (2020-09-04) | |
38 | ||
39 | 1. Add string to time function | |
40 | * [Pull request 152](https://github.com/ignitionrobotics/ign-math/pull/152) | |
41 | ||
42 | 1. Added functions to convert between time_point and secNsec | |
43 | * [Pull request 150](https://github.com/ignitionrobotics/ign-math/pull/150) | |
44 | ||
45 | 1. Fix IGNITION_MATH_XXX_VERSION | |
46 | * [Pull request 151](https://github.com/ignitionrobotics/ign-math/pull/151) | |
47 | ||
48 | 1. Add Max and Min function to Vector2.hh | |
49 | * [Pull request 133](https://github.com/ignitionrobotics/ign-math/pull/133) | |
50 | * [Pull request 148](https://github.com/ignitionrobotics/ign-math/pull/148) | |
51 | * [Issue 71](https://github.com/ignitionrobotics/ign-math/issues/71) | |
52 | ||
53 | 1. Round, Rounded, Correct, Distance(x, y, z, w) and operator< addition to Vector 4 | |
54 | * [Pull request 146](https://github.com/ignitionrobotics/ign-math/pull/146) | |
55 | * [Issue 71](https://github.com/ignitionrobotics/ign-math/issues/71) | |
56 | ||
57 | 1. Sum and normalized functions for Vector4 | |
58 | * [Pull request 140](https://github.com/ignitionrobotics/ign-math/pull/140) | |
59 | * [Issue 71](https://github.com/ignitionrobotics/ign-math/issues/71) | |
60 | ||
61 | 1. Vector4 Ruby tests - Vector4.i and Vector4_TEST.rb | |
62 | * [Pull request 137](https://github.com/ignitionrobotics/ign-math/pull/137) | |
63 | * [Issue 71](https://github.com/ignitionrobotics/ign-math/issues/71) | |
64 | ||
65 | 1. Vector3 to vector4 functions | |
66 | * [Pull request 132](https://github.com/ignitionrobotics/ign-math/pull/132) | |
67 | * [Issue 71](https://github.com/ignitionrobotics/ign-math/issues/71) | |
68 | ||
69 | 1. Update vector2 fuctions from vector3 | |
70 | * [Pull request 130](https://github.com/ignitionrobotics/ign-math/pull/130) | |
71 | * [Issue 71](https://github.com/ignitionrobotics/ign-math/issues/71) | |
72 | ||
73 | 1. Add Abs, Dot and AbsDot and respective tests to Vector4 | |
74 | * [Pull request 135](https://github.com/ignitionrobotics/ign-math/pull/135) | |
75 | * [Issue 71](https://github.com/ignitionrobotics/ign-math/issues/71) | |
76 | ||
77 | 1. Create abs, absDot and Correct functions for Vector2d | |
78 | * [Pull request 143](https://github.com/ignitionrobotics/ign-math/pull/143) | |
79 | * [Issue 71](https://github.com/ignitionrobotics/ign-math/issues/71) | |
80 | ||
81 | 1. Document Ruby tests | |
82 | * [Pull request 145](https://github.com/ignitionrobotics/ign-math/pull/145) | |
83 | ||
84 | 1. Add header for numeric_limits allowing build on ubuntu 16.04 | |
85 | * [Pull request 119](https://github.com/ignitionrobotics/ign-math/pull/119) | |
86 | ||
87 | 1. Add setter/getter for Pose's each element | |
88 | * [Pull request 125](https://github.com/ignitionrobotics/ign-math/pull/125) | |
89 | * [Issue 35](https://github.com/ignitionrobotics/ign-math/issues/35) | |
90 | ||
91 | 1. Implement AxisAlignedBox Volume function | |
92 | * [Pull request 126](https://github.com/ignitionrobotics/ign-math/pull/126) | |
93 | ||
94 | 1. Add operator + for AxisAlignedBox and Vector3. | |
95 | * [Pull request 122](https://github.com/ignitionrobotics/ign-math/pull/122) | |
96 | ||
97 | 1. Make alpha optional when parsing a Color from an input stream. | |
98 | * [Pull request 106](https://github.com/ignitionrobotics/ign-math/pull/106) | |
99 | ||
100 | 1. GitHub actions CI and workflow updates | |
101 | * [Pull request 117](https://github.com/ignitionrobotics/ign-math/pull/117) | |
102 | * [Pull request 139](https://github.com/ignitionrobotics/ign-math/pull/139) | |
103 | * [Pull request 110](https://github.com/ignitionrobotics/ign-math/pull/110) | |
104 | ||
105 | 1. Added a Gauss-Markov Process class. | |
106 | * [BitBucket pull request 342](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/342) | |
107 | ||
108 | 1. Fix bug in Inertial addition of off-diagonal moment of inertia terms with pose offsets. | |
109 | * [BitBucket pull request 344](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/344) | |
110 | ||
111 | 1. Create FAKE_INSTALL target so example compilation can be tested without doing a real install. | |
112 | * Angle: [BitBucket pull request 335](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/335) | |
113 | ||
114 | 1. Updating documentation. | |
115 | * Angle: [BitBucket pull request 325](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/325) | |
116 | ||
117 | 1. GraphAlgorithms: add ToUndirected(DirectedGraph) that copies to an UndirectedGraph. | |
118 | * [BitBucket pull request 332](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/332) | |
119 | ||
120 | 1. Doxygen fixes for graph classes | |
121 | * [BitBucket pull request 331](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/331) | |
122 | ||
123 | ## Ignition Math 6.4.0 | |
3 | 124 | |
4 | 125 | 1. Added a function that rounds up a number to the nearest multiple of |
5 | 126 | another number. |
6 | * [Pull request 318](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/318) | |
127 | * [BitBucket pull request 318](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/318) | |
7 | 128 | |
8 | 129 | ### Ignition Math 6.3.0 |
9 | 130 | |
10 | 1. Added Odometry class that computes odometry for a two wheeled vehicle. | |
11 | * [Pull request 313](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/313) | |
12 | ||
13 | 1. Added RollingMean class. | |
14 | * [Pull request 314](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/314) | |
131 | 1. Added Odometry class that computes odometry for a two wheeled vehicle. | |
132 | * [BitBucket pull request 313](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/313) | |
133 | ||
134 | 1. Added RollingMean class. | |
135 | * [BitBucket pull request 314](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/314) | |
15 | 136 | |
16 | 137 | ### Ignition Math 6.2.0 |
17 | 138 | |
18 | 139 | 1. eigen3: Use linear() instead of rotation() to prevent computation of SVD |
19 | * [Pull request 311](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/311) | |
140 | * [BitBucket pull request 311](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/311) | |
20 | 141 | |
21 | 142 | 1. Change definition of Pose3 `*` operator to fix multiplication order |
22 | * [Pull request 301](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/301) | |
23 | * [Issue 60](https://bitbucket.org/ignitionrobotics/ign-math/issues/60) | |
143 | * [BitBucket pull request 301](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/301) | |
144 | * [Issue 60](https://github.com/ignitionrobotics/ign-math/issues/60) | |
24 | 145 | |
25 | 146 | ### Ignition Math 6.1.0 |
26 | 147 | |
27 | 148 | 1. eigen3: add conversion functions for Eigen::AlignedBox3d <=> ignition::math::AxisAlignedBox |
28 | * [Pull request 302](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/302) | |
149 | * [BitBucket pull request 302](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/302) | |
29 | 150 | |
30 | 151 | ### Ignition Math 6.0.0 |
31 | 152 | |
32 | 153 | 1. Helper function that converts from `std::chrono::steady_clock::duration` to |
33 | 154 | {seconds, nanoseconds}. |
34 | * [Pull request XXX](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/XXX) | |
155 | * [BitBucket pull request XXX](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/XXX) | |
35 | 156 | |
36 | 157 | 1. Upgrade to c++17. |
37 | * [Pull request 268](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/268) | |
158 | * [BitBucket pull request 268](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/268) | |
38 | 159 | |
39 | 160 | ## Ignition Math 5.x |
40 | 161 | |
41 | 162 | ### Ignition Math 5.x.x |
42 | 163 | |
164 | ### Ignition Math 5.1.0 (2019-09-11) | |
165 | ||
166 | 1. GraphAlgorithms: add ToUndirected(DirectedGraph) that copies to an UndirectedGraph. | |
167 | * [BitBucket pull request 332](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/332) | |
168 | ||
169 | 1. Doxygen fixes for graph classes | |
170 | * [BitBucket pull request 331](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/331) | |
171 | ||
43 | 172 | 1. eigen3: Use linear() instead of rotation() to prevent computation of SVD |
44 | * [Pull request 312](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/312) | |
173 | * [BitBucket pull request 312](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/312) | |
45 | 174 | |
46 | 175 | 1. Change definition of Pose3 `*` operator to fix multiplication order |
47 | * [Pull request 301](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/301) | |
48 | * [Issue 60](https://bitbucket.org/ignitionrobotics/ign-math/issues/60) | |
176 | * [BitBucket pull request 301](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/301) | |
177 | * [Issue 60](https://github.com/ignitionrobotics/ign-math/issues/60) | |
49 | 178 | |
50 | 179 | 1. eigen3: add conversion functions for Eigen::AlignedBox3d <=> ignition::math::AxisAlignedBox |
51 | * [Pull request 302](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/302) | |
180 | * [BitBucket pull request 302](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/302) | |
52 | 181 | |
53 | 182 | |
54 | 183 | ### Ignition Math 5.0.0 (2018-12-12) |
55 | 184 | |
56 | 185 | 1. Added a Stopwatch class |
57 | * [Pull request 279](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/279) | |
186 | * [BitBucket pull request 279](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/279) | |
58 | 187 | |
59 | 188 | 1. Added material properties to OrientedBox |
60 | * [Pull request 269](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/269) | |
189 | * [BitBucket pull request 269](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/269) | |
61 | 190 | |
62 | 191 | 1. Added a Cylinder class. |
63 | * [Pull request 250](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/250) | |
192 | * [BitBucket pull request 250](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/250) | |
64 | 193 | |
65 | 194 | 1. The `Box` class has been changed to a templatized class that is not |
66 | 195 | axis-aligned. The previous `Box` functionality is now in the |
67 | 196 | `AxisAlignedBox` class. |
68 | * [Pull request 257](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/257) | |
197 | * [BitBucket pull request 257](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/257) | |
69 | 198 | |
70 | 199 | 1. Added eigen3 component with functions for converting between Eigen and ign-math types. |
71 | * [Pull request 256](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/256) | |
200 | * [BitBucket pull request 256](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/256) | |
72 | 201 | |
73 | 202 | 1. Added a `MassMatrix3::SetFromCylinder` function that uses a `Material` |
74 | 203 | to specify a density. |
75 | * [Pull request 248](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/248) | |
204 | * [BitBucket pull request 248](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/248) | |
76 | 205 | |
77 | 206 | 1. Added a Sphere class. |
78 | * [Pull request 255](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/255) | |
207 | * [BitBucket pull request 255](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/255) | |
79 | 208 | |
80 | 209 | 1. Added a `MassMatrix3::SetFromSphere` function that uses a `Material` to |
81 | 210 | specify a density. |
82 | * [Pull request 247](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/247) | |
211 | * [BitBucket pull request 247](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/247) | |
83 | 212 | |
84 | 213 | 1. Added a `MassMatrix3::SetFromBox` function that uses a `Material` to specify |
85 | 214 | a density. |
86 | * [Pull request 246](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/246) | |
215 | * [BitBucket pull request 246](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/246) | |
87 | 216 | |
88 | 217 | 1. Deprecated mutator functions in MassMatrix3 that lacked a `Set` prefix. |
89 | * [Pull request 262](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/262) | |
218 | * [BitBucket pull request 262](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/262) | |
90 | 219 | |
91 | 220 | 1. Updated the MassMatrix3::ValidMoments(), MassMatrix3::IsValid(), MassMatrix3::IsPositive(), |
92 | 221 | and Inertial::SetMassMatrix functions to accept a tolerance parameter. |
93 | * [Pull request 264](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/264) | |
222 | * [BitBucket pull request 264](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/264) | |
94 | 223 | |
95 | 224 | 1. Add MassMatrix3::IsNearPositive and use it in MassMatrix3::IsValid, use >= instead of > |
96 | 225 | in MassMatrix3::ValidMoments |
97 | * [Pull request 278](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/278) | |
226 | * [BitBucket pull request 278](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/278) | |
98 | 227 | |
99 | 228 | ## Ignition Math 4.x |
100 | 229 | |
102 | 231 | |
103 | 232 | 1. Add Graph::EdgeFromVertices function that return an edge, if one exists, |
104 | 233 | between two vertices. |
105 | * [Pull request 254](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/254) | |
234 | * [BitBucket pull request 254](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/254) | |
106 | 235 | |
107 | 236 | 1. Added multiply assign operator to Matrix4. |
108 | * [Pull request 252](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/252) | |
237 | * [BitBucket pull request 252](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/252) | |
109 | 238 | |
110 | 239 | |
111 | 240 | 1. Add Plane copy constructor and fix cppcheck on artful |
112 | * [Pull request 230](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/230) | |
241 | * [BitBucket pull request 230](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/230) | |
113 | 242 | |
114 | 243 | 1. Added MovingWindowFilter, a copy from Ignition Common. This version will |
115 | 244 | replace the version found in Ignition Common. |
116 | * [Pull request 239](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/239) | |
245 | * [BitBucket pull request 239](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/239) | |
117 | 246 | |
118 | 247 | 1. Added a Material class, which holds information about materials like wood, |
119 | 248 | steel, and iron. |
120 | * [Pull request 243](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/243) | |
249 | * [BitBucket pull request 243](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/243) | |
121 | 250 | |
122 | 251 | ### Ignition Math 4.0.0 (2017-12-26) |
123 | 252 | |
124 | 253 | 1. Use std::stoi and std::stod in math::parse* functions to reduce code |
125 | * [Pull request 224](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/224) | |
126 | * [Issue 50](https://bitbucket.org/ignitionrobotics/ign-math/issues/50) | |
254 | * [BitBucket pull request 224](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/224) | |
255 | * [Issue 50](https://github.com/ignitionrobotics/ign-math/issues/50) | |
127 | 256 | |
128 | 257 | 1. Fixing const-correctness for operator* of Pose3 |
129 | * [Pull request 205](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/205) | |
258 | * [BitBucket pull request 205](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/205) | |
130 | 259 | |
131 | 260 | 1. Deprecate Matrix4::Translate and replace by Matrix4::SetTranslation |
132 | * [Pull request 222](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/222) | |
261 | * [BitBucket pull request 222](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/222) | |
133 | 262 | |
134 | 263 | 1. Use ignition-cmake to simplify build scripts |
135 | * [Pull request 200](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/200) | |
264 | * [BitBucket pull request 200](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/200) | |
136 | 265 | |
137 | 266 | 1. Make constructor SemanticVersion(string) explicit |
138 | * [Pull request 203](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/203) | |
267 | * [BitBucket pull request 203](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/203) | |
139 | 268 | |
140 | 269 | 1. Switch to C++14 |
141 | * [Pull request 180](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/180) | |
270 | * [BitBucket pull request 180](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/180) | |
142 | 271 | |
143 | 272 | 1. Removed the box 'extent' field. The default constructor now sets a box's |
144 | 273 | corners to extrema in order to indicate an uninitialized box. |
145 | * [Pull request 172](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/172) | |
146 | * [Issue 72](https://bitbucket.org/ignitionrobotics/ign-math/issues/72) | |
147 | * [Issue 53](https://bitbucket.org/ignitionrobotics/ign-math/issues/53) | |
274 | * [BitBucket pull request 172](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/172) | |
275 | * [Issue 72](https://github.com/ignitionrobotics/ign-math/issues/72) | |
276 | * [Issue 53](https://github.com/ignitionrobotics/ign-math/issues/53) | |
148 | 277 | |
149 | 278 | 1. Added graph utilites: |
150 | 279 | 1. Added a Vertex class: |
151 | * [Pull request 170](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/170) | |
280 | * [BitBucket pull request 170](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/170) | |
152 | 281 | 1. Added an Edge class: |
153 | * [Pull request 174](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/174) | |
282 | * [BitBucket pull request 174](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/174) | |
154 | 283 | 1. Added a Graph class: |
155 | * [Pull request 175](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/175) | |
284 | * [BitBucket pull request 175](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/175) | |
156 | 285 | 1. Added a GraphAlgorithms class: |
157 | * [Pull request 177](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/177) | |
286 | * [BitBucket pull request 177](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/177) | |
158 | 287 | 1. Added a function to calculate connected components in undirected |
159 | 288 | graphs: |
160 | * [Pull request 190](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/190) | |
289 | * [BitBucket pull request 190](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/190) | |
161 | 290 | 1. Improved the performance of `graph::InDegree()` and `graph::IncidentsTo()`. |
162 | * [Pull request 188](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/188) | |
163 | * [Issue 79](https://bitbucket.org/ignitionrobotics/ign-math/issues/79) | |
291 | * [BitBucket pull request 188](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/188) | |
292 | * [Issue 79](https://github.com/ignitionrobotics/ign-math/issues/79) | |
164 | 293 | |
165 | 294 | 1. Added Inline Versioned Namespace |
166 | * [Pull request 216](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/216/) | |
295 | * [BitBucket pull request 216](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/216/) | |
167 | 296 | |
168 | 297 | ## Ignition Math 3.x |
169 | 298 | |
174 | 303 | ### Ignition Math 3.3.0 (2017-11-27) |
175 | 304 | |
176 | 305 | 1. Fixed frustum falsely saying it contained AABB in some cases |
177 | * [Pull request 193](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/193) | |
178 | * [Issue 78](https://bitbucket.org/ignitionrobotics/ign-math/issues/78) | |
306 | * [BitBucket pull request 193](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/193) | |
307 | * [Issue 78](https://github.com/ignitionrobotics/ign-math/issues/78) | |
179 | 308 | |
180 | 309 | 1. Create consistent bracket operators across all Vector# types |
181 | * [Pull request 181](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/181) | |
310 | * [BitBucket pull request 181](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/181) | |
182 | 311 | |
183 | 312 | 1. Change name to the generic BUILDING_DLL macro to avoid conflicts |
184 | * [Pull request 173](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/173) | |
313 | * [BitBucket pull request 173](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/173) | |
185 | 314 | |
186 | 315 | 1. Fix some compiler warnings |
187 | * [Pull request 196](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/196) | |
316 | * [BitBucket pull request 196](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/196) | |
188 | 317 | |
189 | 318 | 1. Suppress gtest warnings |
190 | * [Pull request 199](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/199) | |
319 | * [BitBucket pull request 199](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/199) | |
191 | 320 | |
192 | 321 | 1. Move private headers to src folder |
193 | * [Pull request 198](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/198) | |
322 | * [BitBucket pull request 198](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/198) | |
194 | 323 | |
195 | 324 | 1. Update configure.bat |
196 | * [Pull request 206](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/206) | |
325 | * [BitBucket pull request 206](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/206) | |
197 | 326 | |
198 | 327 | ### Ignition Math 3.2.0 (2017-05-15) |
199 | 328 | |
200 | 329 | 1. Construct on first use in Rand class |
201 | * [Pull request 165](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/165) | |
330 | * [BitBucket pull request 165](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/165) | |
202 | 331 | |
203 | 332 | 1. Extended Spline API: derivative interpolation, arc length calculation |
204 | 333 | and tangent forcing. |
205 | * [Pull request 162](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/162) | |
334 | * [BitBucket pull request 162](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/162) | |
206 | 335 | |
207 | 336 | ### Ignition Math 3.1.0 (2017-04-11) |
208 | 337 | |
209 | 338 | 1. Added signum functions to Helpers.hh. |
210 | 339 | * Contribution from Martin Pecka |
211 | * [Pull request 153](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/153) | |
340 | * [BitBucket pull request 153](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/153) | |
212 | 341 | |
213 | 342 | ### Ignition Math 3.0.0 (2017-01-05) |
214 | 343 | |
215 | 344 | 1. Deprecate many IGN_* macros in favor of static const variables in Helpers.hh |
216 | * [Pull request 138](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/138) | |
217 | * [Pull request 137](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/137) | |
345 | * [BitBucket pull request 138](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/138) | |
346 | * [BitBucket pull request 137](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/137) | |
218 | 347 | |
219 | 348 | 1. Removed exceptions. Return values should be evaluated to determine if |
220 | 349 | errors have occured. |
221 | * [Pull request 132](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/132) | |
350 | * [BitBucket pull request 132](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/132) | |
222 | 351 | |
223 | 352 | 1. Added `operator=(const Quaternion<T> &_q)` to `Matrix3`. |
224 | * [Pull request 111](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/111) | |
353 | * [BitBucket pull request 111](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/111) | |
225 | 354 | |
226 | 355 | 1. Fix xenial cppcheck |
227 | * [Pull request xxx](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/xxx) | |
356 | * [BitBucket pull request xxx](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/xxx) | |
228 | 357 | |
229 | 358 | 1. Require cmake 2.8.12 |
230 | * [Pull request 76](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/76) | |
359 | * [BitBucket pull request 76](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/76) | |
231 | 360 | |
232 | 361 | 1. Migrate to relocatable CMake package. |
233 | 362 | Contribution from Silvio Traversaro. |
234 | * [Pull request 67](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/67) | |
363 | * [BitBucket pull request 67](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/67) | |
235 | 364 | |
236 | 365 | 1. Fix logic of installation of CMake configuration files in Windows. |
237 | 366 | Contribution from Silvio Traversaro. |
238 | * [Pull request 63](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/63) | |
367 | * [BitBucket pull request 63](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/63) | |
239 | 368 | |
240 | 369 | ## Ignition Math 2.x |
241 | 370 | |
244 | 373 | ## Ignition Math 2.9 (2017-11-22) |
245 | 374 | |
246 | 375 | 1. Fixed frustum falsely saying it contained AABB in some cases |
247 | * [Pull request 193](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/193) | |
376 | * [BitBucket pull request 193](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/193) | |
248 | 377 | |
249 | 378 | 1. Added Color |
250 | * [Pull request 150](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/150) | |
379 | * [BitBucket pull request 150](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/150) | |
251 | 380 | |
252 | 381 | 1. Backport updated configure.bat to ign-math2 and fix cppcheck warnings |
253 | * [Pull request 207](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/207) | |
382 | * [BitBucket pull request 207](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/207) | |
254 | 383 | |
255 | 384 | ### Ignition Math 2.8 |
256 | 385 | |
257 | 386 | ### Ignition Math 2.8.0 |
258 | 387 | |
259 | 388 | 1. Added OrientedBox |
260 | * [Pull request 146](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/146) | |
389 | * [BitBucket pull request 146](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/146) | |
261 | 390 | |
262 | 391 | 1. Added an assignment operator to the Frustum class. |
263 | * [Pull request 144](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/144) | |
392 | * [BitBucket pull request 144](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/144) | |
264 | 393 | |
265 | 394 | ### Ignition Math 2.7 |
266 | 395 | |
267 | 396 | ### Ignition Math 2.7.0 |
268 | 397 | |
269 | 398 | 1. Add static const variables as alternative to macros in Helpers.hh |
270 | * [Pull request 137](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/137) | |
399 | * [BitBucket pull request 137](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/137) | |
271 | 400 | |
272 | 401 | 1. Add new methods for floating numbers: lessOrEqual and greaterOrEqual |
273 | * [Pull request 134](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/134) | |
402 | * [BitBucket pull request 134](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/134) | |
274 | 403 | |
275 | 404 | ### Ignition Math 2.6 |
276 | 405 | |
278 | 407 | |
279 | 408 | 1. Added copy constructor, equality operators and assignment operators to |
280 | 409 | SphericalCoordinates class. |
281 | * [Pull request 131](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/131) | |
410 | * [BitBucket pull request 131](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/131) | |
282 | 411 | |
283 | 412 | 1. Fix Euler angle conversion of quaternions near singularities |
284 | * [Pull request 129](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/129) | |
413 | * [BitBucket pull request 129](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/129) | |
285 | 414 | |
286 | 415 | 1. Backport triangle3, helper functions, equality helper to work with 387 fp unit |
287 | 416 | (Contribution from Rich Mattes). |
288 | * [Pull request 125](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/125) | |
289 | * [Pull request 58](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/58) | |
290 | * [Pull request 56](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/56) | |
417 | * [BitBucket pull request 125](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/125) | |
418 | * [BitBucket pull request 58](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/58) | |
419 | * [BitBucket pull request 56](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/56) | |
291 | 420 | |
292 | 421 | 1. Added Matrix4<T>::LookAt |
293 | * [Pull request 124](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/124) | |
422 | * [BitBucket pull request 124](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/124) | |
294 | 423 | |
295 | 424 | 1. Set Inertial Rotations |
296 | * [Pull request 121](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/121) | |
425 | * [BitBucket pull request 121](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/121) | |
297 | 426 | |
298 | 427 | 1. Added SemanticVersion class |
299 | * [Pull request 120](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/120) | |
428 | * [BitBucket pull request 120](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/120) | |
300 | 429 | |
301 | 430 | ### Ignition Math 2.5 |
302 | 431 | |
303 | 432 | ### Ignition Math 2.5.0 |
304 | 433 | |
305 | 434 | 1. Added PID class |
306 | * [Pull request 117](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/117) | |
435 | * [BitBucket pull request 117](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/117) | |
307 | 436 | |
308 | 437 | 1. Added SphericalCoordinate class |
309 | * [Pull request 108](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/108) | |
438 | * [BitBucket pull request 108](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/108) | |
310 | 439 | |
311 | 440 | ### Ignition Math 2.4 |
312 | 441 | |
314 | 443 | |
315 | 444 | 1. Combine inertial properties of different objects, returning the equivalent |
316 | 445 | inertial properties as if the objects were welded together. |
317 | * [Pull request 115](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/115) | |
446 | * [BitBucket pull request 115](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/115) | |
318 | 447 | |
319 | 448 | #### Ignition Math 2.4.0 |
320 | 449 | |
321 | 450 | 1. New MassMatrix3 class |
322 | * [Pull request 112](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/112) | |
451 | * [BitBucket pull request 112](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/112) | |
323 | 452 | 1. MassMatrix3 helper functions |
324 | * [Pull request 110](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/110) | |
453 | * [BitBucket pull request 110](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/110) | |
325 | 454 | 1. Added Temperature class |
326 | 455 | * A contribution from Shintaro Noda |
327 | * [Pull request 113](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/113) | |
456 | * [BitBucket pull request 113](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/113) | |
328 | 457 | |
329 | 458 | ### Ignition Math 2.3.0 |
330 | 459 | |
331 | 460 | 1. Added simple volumes formulas |
332 | * [Pull request 84](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/84) | |
461 | * [BitBucket pull request 84](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/84) | |
333 | 462 | 1. Add Length and SquaredLength for Vector2 with test |
334 | * [Pull request 73](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/73) | |
463 | * [BitBucket pull request 73](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/73) | |
335 | 464 | 1. Add Equal function with numerical tolerance argument |
336 | * [Pull request 75](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/75) | |
465 | * [BitBucket pull request 75](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/75) | |
337 | 466 | 1. First part of MassMatrix3 class, mostly accessors and modifiers |
338 | * [Pull request 77](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/77) | |
467 | * [BitBucket pull request 77](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/77) | |
339 | 468 | 1. Add Transpose methods for Matrix3,4 with test |
340 | * [Pull request 74](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/74) | |
469 | * [BitBucket pull request 74](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/74) | |
341 | 470 | 1. Multiplication improvements for Vector/Matrix classes |
342 | * [Pull request 69](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/69) | |
471 | * [BitBucket pull request 69](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/69) | |
343 | 472 | 1. Scalar +,- operators for Vector[234] |
344 | * [Pull request 71](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/71) | |
473 | * [BitBucket pull request 71](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/71) | |
345 | 474 | 1. Add Determinant method for Matrix[34] |
346 | * [Pull request 72](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests/72) | |
475 | * [BitBucket pull request 72](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/72) | |
347 | 476 | 1. Fixes for compiling and running tests on Windows 7/Visual Studio 2013 |
348 | 477 | Contribution from Silvio Traversaro. |
349 | * [Pull request 62](https://bitbucket.org/ignitionrobotics/ign-math/pull-request/62) | |
478 | * [BitBucket pull request 62](https://osrf-migration.github.io/ignition-gh-pages/#!/ignitionrobotics/ign-math/pull-requests/62) |
1 | 1 | |
2 | 2 | **Maintainer:** nate AT openrobotics DOT org |
3 | 3 | |
4 | [![Bitbucket open issues](https://img.shields.io/bitbucket/issues-raw/ignitionrobotics/ign-math.svg)](https://bitbucket.org/ignitionrobotics/ign-math/issues) | |
5 | [![Bitbucket open pull requests](https://img.shields.io/bitbucket/pr-raw/ignitionrobotics/ign-math.svg)](https://bitbucket.org/ignitionrobotics/ign-math/pull-requests) | |
4 | [![GitHub open issues](https://img.shields.io/github/issues-raw/ignitionrobotics/ign-math.svg)](https://github.com/ignitionrobotics/ign-math/issues) | |
5 | [![GitHub open pull requests](https://img.shields.io/github/issues-pr-raw/ignitionrobotics/ign-math.svg)](https://github.com/ignitionrobotics/ign-math/pulls) | |
6 | 6 | [![Discourse topics](https://img.shields.io/discourse/https/community.gazebosim.org/topics.svg)](https://community.gazebosim.org) |
7 | 7 | [![Hex.pm](https://img.shields.io/hexpm/l/plug.svg)](https://www.apache.org/licenses/LICENSE-2.0) |
8 | 8 | |
9 | 9 | Build | Status |
10 | 10 | -- | -- |
11 | Test coverage | [![codecov](https://codecov.io/bb/ignitionrobotics/ign-math/branch/default/graph/badge.svg)](https://codecov.io/bb/ignitionrobotics/ign-math) | |
12 | Ubuntu Bionic | [![Build Status](https://build.osrfoundation.org/buildStatus/icon?job=ignition_math-ci-default-bionic-amd64)](https://build.osrfoundation.org/job/ignition_math-ci-default-bionic-amd64) | |
13 | Homebrew | [![Build Status](https://build.osrfoundation.org/buildStatus/icon?job=ignition_math-ci-default-homebrew-amd64)](https://build.osrfoundation.org/job/ignition_math-ci-default-homebrew-amd64) | |
14 | Windows | [![Build Status](https://build.osrfoundation.org/buildStatus/icon?job=ignition_math-ci-default-windows7-amd64)](https://build.osrfoundation.org/job/ignition_math-ci-default-windows7-amd64) | |
11 | Test coverage | [![codecov](https://codecov.io/gh/ignitionrobotics/ign-math/branch/master/graph/badge.svg)](https://codecov.io/gh/ignitionrobotics/ign-math) | |
12 | Ubuntu Bionic | [![Build Status](https://build.osrfoundation.org/buildStatus/icon?job=ignition_math-ci-master-bionic-amd64)](https://build.osrfoundation.org/job/ignition_math-ci-master-bionic-amd64) | |
13 | Homebrew | [![Build Status](https://build.osrfoundation.org/buildStatus/icon?job=ignition_math-ci-master-homebrew-amd64)](https://build.osrfoundation.org/job/ignition_math-ci-master-homebrew-amd64) | |
14 | Windows | [![Build Status](https://build.osrfoundation.org/buildStatus/icon?job=ignition_math-ci-master-windows7-amd64)](https://build.osrfoundation.org/job/ignition_math-ci-master-windows7-amd64) | |
15 | 15 | |
16 | 16 | Ignition Math, a component of [Ignition |
17 | 17 | Robotics](https://ignitionrobotics.org), provides general purpose math |
19 | 19 | |
20 | 20 | # Table of Contents |
21 | 21 | |
22 | [Features](#markdown-header-features) | |
22 | [Features](#features) | |
23 | 23 | |
24 | [Install](#markdown-header-install) | |
24 | [Install](#install) | |
25 | 25 | |
26 | * [Binary Install](#markdown-header-binary-install) | |
26 | [Usage](#usage) | |
27 | 27 | |
28 | * [Source Install](#markdown-header-source-install) | |
28 | [Documentation](#documentation) | |
29 | 29 | |
30 | * [Prerequisites](#markdown-header-prerequisites) | |
30 | [Testing](#testing) | |
31 | 31 | |
32 | * [Building from Source](#markdown-header-building-from-source) | |
32 | [Folder Structure](#folder-structure) | |
33 | 33 | |
34 | [Usage](#markdown-header-usage) | |
34 | [Code of Conduct](#code-of-conduct) | |
35 | 35 | |
36 | [Documentation](#markdown-header-documentation) | |
36 | [Contributing](#code-of-contributing) | |
37 | 37 | |
38 | [Testing](#markdown-header-testing) | |
38 | [Versioning](#versioning) | |
39 | 39 | |
40 | [Folder Structure](#markdown-header-folder-structure) | |
41 | ||
42 | [Code of Conduct](#markdown-header-code-of-conduct) | |
43 | ||
44 | [Contributing](#markdown-header-code-of-contributing) | |
45 | ||
46 | [Versioning](#markdown-header-versioning) | |
47 | ||
48 | [License](#markdown-header-license) | |
40 | [License](#license) | |
49 | 41 | |
50 | 42 | # Features |
51 | 43 | |
59 | 51 | |
60 | 52 | # Install |
61 | 53 | |
62 | We recommend following the [Binary Install](#markdown-header-binary-install) instructions to get up and running as quickly and painlessly as possible. | |
63 | ||
64 | The [Source Install](#markdown-header-source-install) instructions should be used if you need the very latest software improvements, you need to modify the code, or you plan to make a contribution. | |
65 | ||
66 | ## Binary Install | |
67 | ||
68 | On Ubuntu systems, `apt-get` can be used to install `ignition-math`: | |
69 | ||
70 | ``` | |
71 | sudo apt install libignition-math<#>-dev | |
72 | ``` | |
73 | ||
74 | Be sure to replace `<#>` with a number value, such as 1 or 2, depending on | |
75 | which version you need. | |
76 | ||
77 | ## Source Install | |
78 | ||
79 | Source installation can be performed in UNIX systems by first installing the | |
80 | necessary prerequisites followed by building from source. | |
81 | ||
82 | ### Prerequisites | |
83 | ||
84 | The optional Eigen component of Ignition Math requires: | |
85 | ||
86 | * [Eigen](http://eigen.tuxfamily.org/index.php?title=Main_Page). Refer to the [Eigen Documentation](http://eigen.tuxfamily.org/index.php?title=Main_Page#Documentation) for installation instructions. On Ubuntu systems, `apt-get` can be used to install Eigen: | |
87 | ||
88 | ``` | |
89 | sudo apt-get install libeigen3-dev | |
90 | ``` | |
91 | ||
92 | ### Building from source | |
93 | ||
94 | 1. Clone the repository | |
95 | ||
96 | ``` | |
97 | hg clone https://bitbucket.org/ignitionrobotics/ign-math | |
98 | ``` | |
99 | ||
100 | 2. Configure and build | |
101 | ||
102 | ``` | |
103 | cd ign-math; mkdir build; cd build; cmake ..; make | |
104 | ``` | |
105 | ||
106 | 3. Optionally, install Ignition Math | |
107 | ||
108 | ``` | |
109 | sudo make install | |
110 | ``` | |
54 | See the [installation tutorial](https://ignitionrobotics.org/api/math/6.6/install.html). | |
111 | 55 | |
112 | 56 | # Usage |
113 | 57 | |
114 | Please refer to the [examples directory](https://bitbucket.org/ignitionrobotics/ign-math/raw/default/examples/?at=default). | |
58 | Please refer to the [examples directory](https://github.com/ignitionrobotics/ign-math/raw/master/examples/). | |
115 | 59 | |
116 | 60 | # Documentation |
117 | 61 | |
128 | 72 | 2. Clone the repository |
129 | 73 | |
130 | 74 | ``` |
131 | hg clone https://bitbucket.org/ignitionrobotics/ign-math | |
75 | git clone https://github.com/ignitionrobotics/ign-math | |
132 | 76 | ``` |
133 | 77 | |
134 | 78 | 3. Configure and build the documentation. |
147 | 91 | |
148 | 92 | Follow these steps to run tests and static code analysis in your clone of this repository. |
149 | 93 | |
150 | 1. Follow the [source install instruction](#markdown-header-source-install). | |
94 | 1. Follow the [source install instruction](https://ignitionrobotics.org/libs/math#source-install). | |
151 | 95 | |
152 | 96 | 2. Run tests. |
153 | 97 | |
160 | 104 | ``` |
161 | 105 | make codecheck |
162 | 106 | ``` |
107 | ||
108 | ## Ruby Tests | |
109 | ||
110 | ### Usage | |
111 | ||
112 | The C++ classes are available in Ruby code by interface files (`.i`) used by swig to build a C++ extension module. | |
113 | ||
114 | The interfaces and Ruby test codes are in the `src` folder. To use a C++ class in Ruby you need to: | |
115 | ||
116 | 1. Create an interface file describing the class as in Swig and Ruby reference at [The Ruby-to-C/C++ Mapping](http://www.swig.org/Doc1.3/Ruby.html#Ruby_nn11) | |
117 | ||
118 | 2. Include the interface file in `/src/ing_math.i` | |
119 | ||
120 | 3. Create the Ruby file and import the class as in Swig and Ruby reference at [C++ Classes](http://www.swig.org/Doc1.3/Ruby.html#Ruby_nn18) | |
121 | ||
122 | ### Tests | |
123 | ||
124 | `make test` already runs all tests, including the ones made in Ruby, but you can run a Ruby test individually using | |
125 | ||
126 | ``` | |
127 | ctest -R Ruby_TEST.rb | |
128 | ``` | |
163 | 129 | |
164 | 130 | # Folder Structure |
165 | 131 | |
183 | 149 | # Contributing |
184 | 150 | |
185 | 151 | Please see |
186 | [CONTRIBUTING.md](https://bitbucket.org/ignitionrobotics/ign-gazebo/src/406665896aa40bb42f14cf61d48b3d94f2fc5dd8/CONTRIBUTING.md?at=default&fileviewer=file-view-default). | |
152 | [CONTRIBUTING.md](https://github.com/ignitionrobotics/ign-gazebo/blob/master/CONTRIBUTING.md). | |
187 | 153 | |
188 | 154 | # Code of Conduct |
189 | 155 | |
190 | 156 | Please see |
191 | [CODE_OF_CONDUCT.md](https://bitbucket.org/ignitionrobotics/ign-gazebo/src/406665896aa40bb42f14cf61d48b3d94f2fc5dd8/CODE_OF_CONDUCT.md?at=default&fileviewer=file-view-default). | |
157 | [CODE_OF_CONDUCT.md](https://github.com/ignitionrobotics/ign-gazebo/blob/master/CODE_OF_CONDUCT.md). | |
192 | 158 | |
193 | 159 | # Versioning |
194 | 160 | |
196 | 162 | |
197 | 163 | # License |
198 | 164 | |
199 | This library is licensed under [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0). See also the [LICENSE](https://bitbucket.org/ignitionrobotics/ign-math/src/default/LICENSE) file. | |
165 | This library is licensed under [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0). See also the [LICENSE](https://github.com/ignitionrobotics/ign-math/blob/master/LICENSE) file. |
0 | os: | |
1 | - Visual Studio 2017 | |
2 | ||
3 | configuration: | |
4 | - Debug | |
5 | - Release | |
6 | ||
7 | environment: | |
8 | CTEST_OUTPUT_ON_FAILURE: 1 | |
9 | ||
10 | install: | |
11 | - git clone https://github.com/ignitionrobotics/ign-cmake | |
12 | - cd ign-cmake | |
13 | - git checkout ign-cmake2 | |
14 | - md build | |
15 | - cd build | |
16 | - cmake .. -DBUILD_TESTING:BOOL=False | |
17 | - cmake --build . --target INSTALL | |
18 | - cd ../.. | |
19 | build_script: | |
20 | - md build | |
21 | - cd build | |
22 | - cmake .. -DCMAKE_CXX_FLAGS="-WX" | |
23 | - cmake --build . --config %CONFIGURATION% | |
24 | ||
25 | after_build: | |
26 | - cmake --build . --config %CONFIGURATION% --target INSTALL | |
27 | ||
28 | test_script: | |
29 | - cmake --build . --config %CONFIGURATION% --target RUN_TESTS | |
30 | # Build the examples to make sure that find_package(ignition-math* REQUIRED) works | |
31 | - cd ../examples | |
32 | - md build | |
33 | - cd build | |
34 | - cmake .. | |
35 | - cmake --build . --config %CONFIGURATION% | |
36 | - cd .. | |
37 |
0 | image: ubuntu:bionic | |
1 | ||
2 | pipelines: | |
3 | default: | |
4 | - step: | |
5 | script: | |
6 | - apt-get update | |
7 | - apt-get -y install cmake build-essential curl git cppcheck ruby-dev swig g++-8 libeigen3-dev doxygen | |
8 | - update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 800 --slave /usr/bin/g++ g++ /usr/bin/g++-8 --slave /usr/bin/gcov gcov /usr/bin/gcov-8 | |
9 | - gcc -v | |
10 | - g++ -v | |
11 | - gcov -v | |
12 | # lcov | |
13 | - git clone https://github.com/linux-test-project/lcov.git | |
14 | - cd lcov | |
15 | # see https://github.com/linux-test-project/lcov/issues/55 | |
16 | - git checkout 1e0df571 | |
17 | - make install | |
18 | - cd .. | |
19 | # Ignition cmake | |
20 | - echo "deb http://packages.osrfoundation.org/gazebo/ubuntu-stable bionic main" > /etc/apt/sources.list.d/gazebo-stable.list | |
21 | # - echo "deb http://packages.osrfoundation.org/gazebo/ubuntu-prerelease bionic main" > /etc/apt/sources.list.d/gazebo-prerelease.list | |
22 | - apt-key adv --keyserver keyserver.ubuntu.com --recv-keys D2486D2DD83DB69272AFE98867170598AF249743 | |
23 | - apt-get update | |
24 | - apt-get -y install | |
25 | libignition-cmake2-dev | |
26 | # Ignition math | |
27 | - mkdir build | |
28 | - cd build | |
29 | - cmake .. -DCMAKE_BUILD_TYPE=coverage | |
30 | - make | |
31 | # Make sure documentation generation generated no warnings. | |
32 | - make doc | |
33 | - bash <(curl -s https://github.com/ignitionrobotics/ign-cmake/raw/master/tools/doc_check.sh) | |
34 | - make test | |
35 | - make coverage | |
36 | # Use a special version of codecov for handling gcc8 output. | |
37 | - bash <(curl -s https://raw.githubusercontent.com/codecov/codecov-bash/4678d212cce2078bbaaf5027af0c0dafaad6a095/codecov) -X gcovout -X gcov | |
38 | - make codecheck | |
39 | - make install | |
40 | # Examples | |
41 | - cd .. | |
42 | - cd examples | |
43 | - mkdir build | |
44 | - cd build | |
45 | - cmake .. | |
46 | - make | |
47 | - ./graph_example |
2 | 2 | # Find the Ignition-Math library |
3 | 3 | set(IGN_MATH_VER 6) |
4 | 4 | find_package(ignition-math${IGN_MATH_VER} REQUIRED) |
5 | ||
6 | add_executable(angle_example angle_example.cc) | |
7 | target_link_libraries(angle_example ignition-math${IGN_MATH_VER}::ignition-math${IGN_MATH_VER}) | |
8 | ||
9 | add_executable(gauss_markov_process gauss_markov_process_example.cc) | |
10 | target_link_libraries(gauss_markov_process ignition-math${IGN_MATH_VER}::ignition-math${IGN_MATH_VER}) | |
5 | 11 | |
6 | 12 | add_executable(vector2_example vector2_example.cc) |
7 | 13 | target_link_libraries(vector2_example ignition-math${IGN_MATH_VER}::ignition-math${IGN_MATH_VER}) |
0 | /* | |
1 | * Copyright (C) 2019 Open Source Robotics Foundation | |
2 | * | |
3 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
4 | * you may not use this file except in compliance with the License. | |
5 | * You may obtain a copy of the License at | |
6 | * | |
7 | * http://www.apache.org/licenses/LICENSE-2.0 | |
8 | * | |
9 | * Unless required by applicable law or agreed to in writing, software | |
10 | * distributed under the License is distributed on an "AS IS" BASIS, | |
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 | * See the License for the specific language governing permissions and | |
13 | * limitations under the License. | |
14 | * | |
15 | */ | |
16 | //! [complete] | |
17 | #include <iostream> | |
18 | #include <ignition/math/Angle.hh> | |
19 | ||
20 | int main(int argc, char **argv) | |
21 | { | |
22 | // Create an angle. | |
23 | ignition::math::Angle a; | |
24 | ||
25 | // A default constructed angle should be zero. | |
26 | std::cout << "The angle 'a' should be zero: " << a << std::endl; | |
27 | a = ignition::math::Angle::Pi; | |
28 | ||
29 | // Output the angle in radians and degrees. | |
30 | std::cout << "Pi in radians: " << a << std::endl; | |
31 | std::cout << "Pi in degrees: " << a.Degree() << std::endl; | |
32 | ||
33 | // The Angle class overloads the +=, and many other, math operators. | |
34 | a += ignition::math::Angle::HalfPi; | |
35 | std::cout << "Pi + PI/2 in radians: " << a << std::endl; | |
36 | std::cout << "Normalized to the range -Pi and Pi: " | |
37 | << a.Normalized() << std::endl; | |
38 | } | |
39 | //! [complete] |
0 | /* | |
1 | * Copyright (C) 2020 Open Source Robotics Foundation | |
2 | * | |
3 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
4 | * you may not use this file except in compliance with the License. | |
5 | * You may obtain a copy of the License at | |
6 | * | |
7 | * http://www.apache.org/licenses/LICENSE-2.0 | |
8 | * | |
9 | * Unless required by applicable law or agreed to in writing, software | |
10 | * distributed under the License is distributed on an "AS IS" BASIS, | |
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 | * See the License for the specific language governing permissions and | |
13 | * limitations under the License. | |
14 | * | |
15 | */ | |
16 | //! [complete] | |
17 | #include <iostream> | |
18 | #include <ignition/math/GaussMarkovProcess.hh> | |
19 | ||
20 | // You can plot the data generated by this program by following these | |
21 | // steps. | |
22 | // | |
23 | // 1. Run this program and save the output to a file: | |
24 | // ./gauss_markov_process > plot.data | |
25 | // | |
26 | // 2. Use gnuplot to create a plot: | |
27 | // gnuplot -e 'set terminal jpeg; plot "plot.data" with lines' > out.jpg | |
28 | int main(int argc, char **argv) | |
29 | { | |
30 | // Create the process with: | |
31 | // * Start value of 20.2 | |
32 | // * Theta (rate at which the process should approach the mean) of 0.1 | |
33 | // * Mu (mean value) 0. | |
34 | // * Sigma (volatility) of 0.5. | |
35 | ignition::math::GaussMarkovProcess gmp(20.2, 0.1, 0, 0.5); | |
36 | ||
37 | std::chrono::steady_clock::duration dt = std::chrono::milliseconds(100); | |
38 | ||
39 | // This process should decrease toward the mean value of 0. | |
40 | // With noise of 0.5, the process will walk a bit. | |
41 | for (int i = 0; i < 1000; ++i) | |
42 | { | |
43 | double value = gmp.Update(dt); | |
44 | std::cout << value << std::endl; | |
45 | } | |
46 | ||
47 | return 0; | |
48 | } | |
49 | //! [complete] |
20 | 20 | #include <ignition/math/Helpers.hh> |
21 | 21 | #include <ignition/math/config.hh> |
22 | 22 | |
23 | /// \def IGN_RTOD(d) | |
23 | 24 | /// \brief Macro that converts radians to degrees |
24 | /// \param[in] radians | |
25 | /// \param[in] r radians | |
25 | 26 | /// \return degrees |
26 | 27 | #define IGN_RTOD(r) ((r) * 180 / IGN_PI) |
27 | 28 | |
29 | /// \def IGN_DTOR(d) | |
28 | 30 | /// \brief Converts degrees to radians |
29 | /// \param[in] degrees | |
31 | /// \param[in] d degrees | |
30 | 32 | /// \return radians |
31 | 33 | #define IGN_DTOR(d) ((d) * IGN_PI / 180) |
32 | 34 | |
35 | /// \def IGN_NORMALIZE(a) | |
33 | 36 | /// \brief Macro that normalizes an angle in the range -Pi to Pi |
34 | /// \param[in] angle | |
37 | /// \param[in] a angle | |
35 | 38 | /// \return the angle, in range |
36 | 39 | #define IGN_NORMALIZE(a) (atan2(sin(a), cos(a))) |
37 | 40 | |
43 | 46 | inline namespace IGNITION_MATH_VERSION_NAMESPACE { |
44 | 47 | // |
45 | 48 | /// \class Angle Angle.hh ignition/math/Angle.hh |
46 | /// \brief An angle and related functions. | |
49 | /// \brief The Angle class is used to simplify and clarify the use of | |
50 | /// radians and degrees measurements. A default constructed Angle instance | |
51 | /// has a value of zero radians/degrees. | |
52 | /// | |
53 | /// Unless otherwise specified, the Angle class assumes units are in | |
54 | /// radians. An example of this are the stream insertion (<<) and | |
55 | /// extraction (>>) operators. | |
56 | /// | |
57 | /// ## Example | |
58 | /// | |
59 | /// \snippet examples/angle_example.cc complete | |
47 | 60 | class IGNITION_MATH_VISIBLE Angle |
48 | 61 | { |
49 | /// \brief math::Angle(0) | |
62 | /// \brief An angle with a value of zero. | |
63 | /// Equivalent to math::Angle(0). | |
50 | 64 | public: static const Angle Zero; |
51 | 65 | |
52 | /// \brief math::Angle(IGN_PI) | |
66 | /// \brief An angle with a value of Pi. | |
67 | /// Equivalent to math::Angle(IGN_PI). | |
53 | 68 | public: static const Angle Pi; |
54 | 69 | |
55 | /// \brief math::Angle(IGN_PI * 0.5) | |
70 | /// \brief An angle with a value of Pi * 0.5. | |
71 | /// Equivalent to math::Angle(IGN_PI * 0.5). | |
56 | 72 | public: static const Angle HalfPi; |
57 | 73 | |
58 | /// \brief math::Angle(IGN_PI * 2) | |
74 | /// \brief An angle with a value of Pi * 2. | |
75 | /// Equivalent to math::Angle(IGN_PI * 2). | |
59 | 76 | public: static const Angle TwoPi; |
60 | 77 | |
61 | /// \brief Constructor | |
78 | /// \brief Default constructor that initializes an Angle to zero | |
79 | /// radians/degrees. | |
62 | 80 | public: Angle(); |
63 | 81 | |
64 | /// \brief Conversion Constructor | |
65 | /// \param[in] _radian Radians | |
82 | /// \brief Conversion constructor that initializes an Angle to the | |
83 | /// specified radians. This constructor supports implicit conversion | |
84 | /// of a double to an Angle. For example: | |
85 | /// | |
86 | /// \code | |
87 | /// Angle a = 3.14; | |
88 | /// \endcode | |
89 | // | |
90 | /// \param[in] _radian The radians used to initialize this Angle. | |
66 | 91 | // cppcheck-suppress noExplicitConstructor |
67 | 92 | public: Angle(const double _radian); |
68 | 93 | |
69 | /// \brief Copy constructor | |
94 | /// \brief Copy constructor that initializes this Angle to the value | |
95 | /// contained in the _angle parameter. | |
70 | 96 | /// \param[in] _angle Angle to copy |
71 | 97 | public: Angle(const Angle &_angle); |
72 | 98 | |
73 | 99 | /// \brief Destructor |
74 | 100 | public: virtual ~Angle(); |
75 | 101 | |
76 | /// \brief Set the value from an angle in radians | |
77 | /// \param[in] _radian Radian value | |
102 | /// \brief Set the value from an angle in radians. | |
103 | /// \param[in] _radian Radian value. | |
104 | /// \sa SetRadian(double) | |
78 | 105 | public: void Radian(double _radian); |
106 | ||
107 | /// \brief Set the value from an angle in radians. | |
108 | /// \param[in] _radian Radian value. | |
109 | public: void SetRadian(double _radian); | |
79 | 110 | |
80 | 111 | /// \brief Set the value from an angle in degrees |
81 | 112 | /// \param[in] _degree Degree value |
113 | /// \sa SetDegree(double) | |
82 | 114 | public: void Degree(double _degree); |
83 | 115 | |
84 | /// \brief Get the angle in radians | |
85 | /// \return double containing the angle's radian value | |
116 | /// \brief Set the value from an angle in degrees | |
117 | /// \param[in] _degree Degree value | |
118 | public: void SetDegree(double _degree); | |
119 | ||
120 | /// \brief Get the angle in radians. | |
121 | /// \return Double containing the angle's radian value. | |
86 | 122 | public: double Radian() const; |
87 | 123 | |
88 | /// \brief Get the angle in degrees | |
89 | /// \return double containing the angle's degree value | |
124 | /// \brief Get the angle in degrees. | |
125 | /// \return Double containing the angle's degree value. | |
90 | 126 | public: double Degree() const; |
91 | 127 | |
92 | /// \brief Normalize the angle in the range -Pi to Pi | |
128 | /// \brief Normalize the angle in the range -Pi to Pi. This | |
129 | /// modifies the value contained in this Angle instance. | |
130 | /// \sa Normalized() | |
93 | 131 | public: void Normalize(); |
132 | ||
133 | /// \brief Return the normalized angle in the range -Pi to Pi. This | |
134 | /// does not modify the value contained in this Angle instance. | |
135 | /// \return The normalized value of this Angle. | |
136 | public: Angle Normalized() const; | |
94 | 137 | |
95 | 138 | /// \brief Return the angle's radian value |
96 | 139 | /// \return double containing the angle's radian value |
103 | 146 | return value; |
104 | 147 | } |
105 | 148 | |
106 | /// \brief Substraction, result = this - _angle | |
107 | /// \param[in] _angle Angle for substraction | |
108 | /// \return the new angle | |
149 | /// \brief Subtraction operator, result = this - _angle. | |
150 | /// \param[in] _angle Angle for subtraction. | |
151 | /// \return The new angle. | |
109 | 152 | public: Angle operator-(const Angle &_angle) const; |
110 | 153 | |
111 | /// \brief Addition operator, result = this + _angle | |
112 | /// \param[in] _angle Angle for addition | |
113 | /// \return the new angle | |
154 | /// \brief Addition operator, result = this + _angle. | |
155 | /// \param[in] _angle Angle for addition. | |
156 | /// \return The new angle. | |
114 | 157 | public: Angle operator+(const Angle &_angle) const; |
115 | 158 | |
116 | /// \brief Multiplication operator, result = this * _angle | |
117 | /// \param[in] _angle Angle for multiplication | |
118 | /// \return the new angle | |
159 | /// \brief Multiplication operator, result = this * _angle. | |
160 | /// \param[in] _angle Angle for multiplication. | |
161 | /// \return The new angle | |
119 | 162 | public: Angle operator*(const Angle &_angle) const; |
120 | 163 | |
121 | /// \brief Division, result = this / _angle | |
122 | /// \param[in] _angle Angle for division | |
123 | /// \return the new angle | |
164 | /// \brief Division operator, result = this / _angle. | |
165 | /// \param[in] _angle Angle for division. | |
166 | /// \return The new angle. | |
124 | 167 | public: Angle operator/(const Angle &_angle) const; |
125 | 168 | |
126 | /// \brief Subtraction set, this = this - _angle | |
127 | /// \param[in] _angle Angle for subtraction | |
128 | /// \return angle | |
169 | /// \brief Subtraction set operator, this = this - _angle. | |
170 | /// \param[in] _angle Angle for subtraction. | |
171 | /// \return The new angle. | |
129 | 172 | public: Angle operator-=(const Angle &_angle); |
130 | 173 | |
131 | /// \brief Addition set, this = this + _angle | |
132 | /// \param[in] _angle Angle for addition | |
133 | /// \return angle | |
174 | /// \brief Addition set operator, this = this + _angle. | |
175 | /// \param[in] _angle Angle for addition. | |
176 | /// \return The new angle. | |
134 | 177 | public: Angle operator+=(const Angle &_angle); |
135 | 178 | |
136 | /// \brief Multiplication set, this = this * _angle | |
137 | /// \param[in] _angle Angle for multiplication | |
138 | /// \return angle | |
179 | /// \brief Multiplication set operator, this = this * _angle. | |
180 | /// \param[in] _angle Angle for multiplication. | |
181 | /// \return The new angle. | |
139 | 182 | public: Angle operator*=(const Angle &_angle); |
140 | 183 | |
141 | /// \brief Division set, this = this / _angle | |
142 | /// \param[in] _angle Angle for division | |
143 | /// \return angle | |
184 | /// \brief Division set operator, this = this / _angle. | |
185 | /// \param[in] _angle Angle for division. | |
186 | /// \return The new angle. | |
144 | 187 | public: Angle operator/=(const Angle &_angle); |
145 | 188 | |
146 | /// \brief Equality operator, result = this == _angle | |
147 | /// \param[in] _angle Angle to check for equality | |
148 | /// \return true if this == _angle | |
189 | /// \brief Equality operator, result = this == _angle. | |
190 | /// \param[in] _angle Angle to check for equality. | |
191 | /// \return True if this == _angle. | |
149 | 192 | public: bool operator==(const Angle &_angle) const; |
150 | 193 | |
151 | /// \brief Inequality | |
152 | /// \param[in] _angle Angle to check for inequality | |
153 | /// \return true if this != _angle | |
194 | /// \brief Inequality operator | |
195 | /// \param[in] _angle Angle to check for inequality. | |
196 | /// \return True if this != _angle. | |
154 | 197 | public: bool operator!=(const Angle &_angle) const; |
155 | 198 | |
156 | /// \brief Less than operator | |
157 | /// \param[in] _angle Angle to check | |
158 | /// \return true if this < _angle | |
199 | /// \brief Less than operator. | |
200 | /// \param[in] _angle Angle to check. | |
201 | /// \return True if this < _angle. | |
159 | 202 | public: bool operator<(const Angle &_angle) const; |
160 | 203 | |
161 | /// \brief Less or equal operator | |
162 | /// \param[in] _angle Angle to check | |
163 | /// \return true if this <= _angle | |
204 | /// \brief Less than or equal operator. | |
205 | /// \param[in] _angle Angle to check. | |
206 | /// \return True if this <= _angle. | |
164 | 207 | public: bool operator<=(const Angle &_angle) const; |
165 | 208 | |
166 | /// \brief Greater than operator | |
167 | /// \param[in] _angle Angle to check | |
168 | /// \return true if this > _angle | |
209 | /// \brief Greater than operator. | |
210 | /// \param[in] _angle Angle to check. | |
211 | /// \return True if this > _angle. | |
169 | 212 | public: bool operator>(const Angle &_angle) const; |
170 | 213 | |
171 | /// \brief Greater or equal operator | |
172 | /// \param[in] _angle Angle to check | |
173 | /// \return true if this >= _angle | |
214 | /// \brief Greater than or equal operator. | |
215 | /// \param[in] _angle Angle to check. | |
216 | /// \return True if this >= _angle. | |
174 | 217 | public: bool operator>=(const Angle &_angle) const; |
175 | 218 | |
176 | /// \brief Stream insertion operator. Outputs in degrees | |
177 | /// \param[in] _out output stream | |
178 | /// \param[in] _a angle to output | |
179 | /// \return The output stream | |
219 | /// \brief Stream insertion operator. Outputs in radians. | |
220 | /// \param[in] _out Output stream. | |
221 | /// \param[in] _a Angle to output. | |
222 | /// \return The output stream. | |
180 | 223 | public: friend std::ostream &operator<<(std::ostream &_out, |
181 | 224 | const ignition::math::Angle &_a) |
182 | 225 | { |
184 | 227 | return _out; |
185 | 228 | } |
186 | 229 | |
187 | /// \brief Stream extraction operator. Assumes input is in radians | |
188 | /// \param in input stream | |
189 | /// \param pt angle to read value into | |
190 | /// \return The input stream | |
230 | /// \brief Stream extraction operator. Assumes input is in radians. | |
231 | /// \param[in,out] _in Input stream. | |
232 | /// \param[out] _a Angle to read value into. | |
233 | /// \return The input stream. | |
191 | 234 | public: friend std::istream &operator>>(std::istream &_in, |
192 | 235 | ignition::math::Angle &_a) |
193 | 236 | { |
198 | 241 | } |
199 | 242 | |
200 | 243 | /// The angle in radians |
201 | private: double value; | |
244 | private: double value{0}; | |
202 | 245 | }; |
203 | 246 | } |
204 | 247 | } |
125 | 125 | /// \param _v The vector to use during subtraction |
126 | 126 | /// \return The new box |
127 | 127 | public: AxisAlignedBox operator-(const Vector3d &_v); |
128 | ||
129 | /// \brief Add a vector to the min and max values | |
130 | /// \param _v The vector to use during addition | |
131 | /// \return The new box | |
132 | public: AxisAlignedBox operator+(const Vector3d &_v); | |
128 | 133 | |
129 | 134 | /// \brief Output operator |
130 | 135 | /// \param[in] _out Output stream |
265 | 270 | /// \brief Get the mass matrix for this box. This function |
266 | 271 | /// is only meaningful if the box's size and material |
267 | 272 | /// have been set. |
268 | /// \param[out] _massMatrix The computed mass matrix will be stored | |
273 | /// \param[out] _massMat The computed mass matrix will be stored | |
269 | 274 | /// here. |
270 | 275 | /// \return False if computation of the mass matrix failed, which |
271 | 276 | /// could be due to an invalid size (<=0) or density (<=0). |
158 | 158 | /// \brief Get the mass matrix for this box. This function |
159 | 159 | /// is only meaningful if the box's size and material |
160 | 160 | /// have been set. |
161 | /// \param[out] _massMatrix The computed mass matrix will be stored | |
161 | /// \param[out] _massMat The computed mass matrix will be stored | |
162 | 162 | /// here. |
163 | 163 | /// \return False if computation of the mass matrix failed, which |
164 | 164 | /// could be due to an invalid size (<=0) or density (<=0). |
0 | /* | |
1 | * Copyright (C) 2020 Open Source Robotics Foundation | |
2 | * | |
3 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
4 | * you may not use this file except in compliance with the License. | |
5 | * You may obtain a copy of the License at | |
6 | * | |
7 | * http://www.apache.org/licenses/LICENSE-2.0 | |
8 | * | |
9 | * Unless required by applicable law or agreed to in writing, software | |
10 | * distributed under the License is distributed on an "AS IS" BASIS, | |
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 | * See the License for the specific language governing permissions and | |
13 | * limitations under the License. | |
14 | * | |
15 | */ | |
16 | #ifndef IGNITION_MATH_CAPSULE_HH_ | |
17 | #define IGNITION_MATH_CAPSULE_HH_ | |
18 | ||
19 | #include <optional> | |
20 | #include "ignition/math/MassMatrix3.hh" | |
21 | #include "ignition/math/Material.hh" | |
22 | ||
23 | namespace ignition | |
24 | { | |
25 | namespace math | |
26 | { | |
27 | // Foward declarations | |
28 | class CapsulePrivate; | |
29 | ||
30 | // Inline bracket to help doxygen filtering. | |
31 | inline namespace IGNITION_MATH_VERSION_NAMESPACE { | |
32 | // | |
33 | /// \class Capsule Capsule.hh ignition/math/Capsule.hh | |
34 | /// \brief A representation of a capsule or sphere-capped cylinder. | |
35 | /// | |
36 | /// The capsule class supports defining a capsule with a radius, | |
37 | /// length, and material properties. The shape is equivalent to a cylinder | |
38 | /// aligned with the Z-axis and capped with hemispheres. Radius and | |
39 | /// length are in meters. See Material for more on material properties. | |
40 | /// \tparam Precision Scalar numeric type. | |
41 | template<typename Precision> | |
42 | class Capsule | |
43 | { | |
44 | /// \brief Default constructor. The default radius and length are both | |
45 | /// zero. | |
46 | public: Capsule() = default; | |
47 | ||
48 | /// \brief Construct a capsule with a length and radius. | |
49 | /// \param[in] _length Length of the capsule. | |
50 | /// \param[in] _radius Radius of the capsule. | |
51 | public: Capsule(const Precision _length, const Precision _radius); | |
52 | ||
53 | /// \brief Construct a capsule with a length, radius, and material. | |
54 | /// \param[in] _length Length of the capsule. | |
55 | /// \param[in] _radius Radius of the capsule. | |
56 | /// \param[in] _mat Material property for the capsule. | |
57 | public: Capsule(const Precision _length, const Precision _radius, | |
58 | const Material &_mat); | |
59 | ||
60 | /// \brief Get the radius in meters. | |
61 | /// \return The radius of the capsule in meters. | |
62 | public: Precision Radius() const; | |
63 | ||
64 | /// \brief Set the radius in meters. | |
65 | /// \param[in] _radius The radius of the capsule in meters. | |
66 | public: void SetRadius(const Precision _radius); | |
67 | ||
68 | /// \brief Get the length in meters. | |
69 | /// \return The length of the capsule in meters. | |
70 | public: Precision Length() const; | |
71 | ||
72 | /// \brief Set the length in meters. | |
73 | /// \param[in] _length The length of the capsule in meters. | |
74 | public: void SetLength(const Precision _length); | |
75 | ||
76 | /// \brief Get the material associated with this capsule. | |
77 | /// \return The material assigned to this capsule | |
78 | public: const Material &Mat() const; | |
79 | ||
80 | /// \brief Set the material associated with this capsule. | |
81 | /// \param[in] _mat The material assigned to this capsule | |
82 | public: void SetMat(const Material &_mat); | |
83 | ||
84 | /// \brief Get the mass matrix for this capsule. This function | |
85 | /// is only meaningful if the capsule's radius, length, and material | |
86 | /// have been set. | |
87 | /// \return The computed mass matrix if parameters are valid | |
88 | /// (radius > 0), (length > 0), and (density > 0). Otherwise | |
89 | /// std::nullopt is returned. | |
90 | public: std::optional< MassMatrix3<Precision> > MassMatrix() const; | |
91 | ||
92 | /// \brief Check if this capsule is equal to the provided capsule. | |
93 | /// Radius, length, and material properties will be checked. | |
94 | public: bool operator==(const Capsule &_capsule) const; | |
95 | ||
96 | /// \brief Get the volume of the capsule in m^3. | |
97 | /// \return Volume of the capsule in m^3. | |
98 | public: Precision Volume() const; | |
99 | ||
100 | /// \brief Compute the capsule's density given a mass value. The | |
101 | /// capsule is assumed to be solid with uniform density. This | |
102 | /// function requires the capsule's radius and length to be set to | |
103 | /// values greater than zero. The Material of the capsule is ignored. | |
104 | /// \param[in] _mass Mass of the capsule, in kg. This value should be | |
105 | /// greater than zero. | |
106 | /// \return Density of the capsule in kg/m^3. A NaN is returned | |
107 | /// if radius, length or _mass is <= 0. | |
108 | public: Precision DensityFromMass(const Precision _mass) const; | |
109 | ||
110 | /// \brief Set the density of this capsule based on a mass value. | |
111 | /// Density is computed using | |
112 | /// Precision DensityFromMass(const Precision _mass) const. The | |
113 | /// capsule is assumed to be solid with uniform density. This | |
114 | /// function requires the capsule's radius and length to be set to | |
115 | /// values greater than zero. The existing Material density value is | |
116 | /// overwritten only if the return value from this true. | |
117 | /// \param[in] _mass Mass of the capsule, in kg. This value should be | |
118 | /// greater than zero. | |
119 | /// \return True if the density was set. False is returned if the | |
120 | /// capsule's radius, length, or the _mass value are <= 0. | |
121 | /// \sa Precision DensityFromMass(const Precision _mass) const | |
122 | public: bool SetDensityFromMass(const Precision _mass); | |
123 | ||
124 | /// \brief Radius of the capsule. | |
125 | private: Precision radius = 0.0; | |
126 | ||
127 | /// \brief Length of the capsule. | |
128 | private: Precision length = 0.0; | |
129 | ||
130 | /// \brief the capsule's material. | |
131 | private: Material material; | |
132 | }; | |
133 | ||
134 | /// \typedef Capsule<int> Capsulei | |
135 | /// \brief Capsule with integer precision. | |
136 | typedef Capsule<int> Capsulei; | |
137 | ||
138 | /// \typedef Capsule<double> Capsuled | |
139 | /// \brief Capsule with double precision. | |
140 | typedef Capsule<double> Capsuled; | |
141 | ||
142 | /// \typedef Capsule<float> Capsulef | |
143 | /// \brief Capsule with float precision. | |
144 | typedef Capsule<float> Capsulef; | |
145 | } | |
146 | } | |
147 | } | |
148 | #include "ignition/math/detail/Capsule.hh" | |
149 | ||
150 | #endif |
17 | 17 | #define IGNITION_MATH_COLOR_HH_ |
18 | 18 | |
19 | 19 | #include <iostream> |
20 | #include <cctype> | |
20 | 21 | |
21 | 22 | #include <ignition/math/Helpers.hh> |
22 | 23 | #include <ignition/math/Vector3.hh> |
51 | 52 | /// \brief (0, 1, 1) |
52 | 53 | public: static const Color Cyan; |
53 | 54 | |
54 | /// \def RGBA | |
55 | /// \typedef RGBA | |
55 | 56 | /// \brief A RGBA packed value as an unsigned int |
56 | 57 | public: typedef unsigned int RGBA; |
57 | 58 | |
58 | /// \def BGRA | |
59 | /// \typedef BGRA | |
59 | 60 | /// \brief A BGRA packed value as an unsigned int |
60 | 61 | public: typedef unsigned int BGRA; |
61 | 62 | |
62 | /// \def ARGB | |
63 | /// \typedef ARGB | |
63 | 64 | /// \brief A ARGB packed value as an unsigned int |
64 | 65 | public: typedef unsigned int ARGB; |
65 | 66 | |
66 | /// \def ABGR | |
67 | /// \typedef ABGR | |
67 | 68 | /// \brief A ABGR packed value as an unsigned int |
68 | 69 | public: typedef unsigned int ABGR; |
69 | 70 | |
246 | 247 | } |
247 | 248 | |
248 | 249 | /// \brief Stream insertion operator |
249 | /// \param[in] _in the input stream | |
250 | /// \param[in] _in the input stream. If the input stream does not include | |
251 | /// an alpha value, a default alpha value of 1.0 will be used. | |
250 | 252 | /// \param[in] _pt |
251 | 253 | public: friend std::istream &operator>> (std::istream &_in, Color &_pt) |
252 | 254 | { |
253 | 255 | // Skip white spaces |
254 | 256 | _in.setf(std::ios_base::skipws); |
255 | _in >> _pt.r >> _pt.g >> _pt.b >> _pt.a; | |
257 | _in >> _pt.r >> _pt.g >> _pt.b; | |
258 | // Since alpha is optional, check if it's there before parsing | |
259 | while (!_in.eof() && std::isspace(_in.peek())) | |
260 | { | |
261 | _in.get(); | |
262 | } | |
263 | if (!_in.eof()) | |
264 | { | |
265 | _in >> _pt.a; | |
266 | } | |
267 | else | |
268 | { | |
269 | _pt.a = 1.0; | |
270 | } | |
256 | 271 | return _in; |
257 | 272 | } |
258 | 273 | |
289 | 304 | public: float &A(); |
290 | 305 | |
291 | 306 | /// \brief Set the red value |
292 | /// \param _r New red value | |
307 | /// \param[in] _r New red value | |
293 | 308 | public: void R(const float _r); |
294 | 309 | |
295 | 310 | /// \brief Set the green value |
296 | /// \param _r New green value | |
311 | /// \param[in] _g New green value | |
297 | 312 | public: void G(const float _g); |
298 | 313 | |
299 | 314 | /// \brief Set the blue value |
300 | /// \param _r New blue value | |
315 | /// \param[in] _b New blue value | |
301 | 316 | public: void B(const float _b); |
302 | 317 | |
303 | 318 | /// \brief Set the alpha value |
304 | /// \param _r New alpha value | |
319 | /// \param[in] _a New alpha value | |
305 | 320 | public: void A(const float _a); |
306 | 321 | |
307 | 322 | /// \brief Red value |
31 | 31 | inline namespace IGNITION_MATH_VERSION_NAMESPACE { |
32 | 32 | // |
33 | 33 | /// \class Cylinder Cylinder.hh ignition/math/Cylinder.hh |
34 | /// \brief A represntation of a cylinder. | |
34 | /// \brief A representation of a cylinder. | |
35 | 35 | /// |
36 | 36 | /// The cylinder class supports defining a cylinder with a radius, |
37 | 37 | /// length, rotational offset, and material properties. Radius and |
115 | 115 | /// \brief Get the mass matrix for this cylinder. This function |
116 | 116 | /// is only meaningful if the cylinder's radius, length, and material |
117 | 117 | /// have been set. Optionally, set the rotational offset. |
118 | /// \param[out] _massMatrix The computed mass matrix will be stored | |
118 | /// \param[out] _massMat The computed mass matrix will be stored | |
119 | 119 | /// here. |
120 | 120 | /// \return False if computation of the mass matrix failed, which |
121 | 121 | /// could be due to an invalid radius (<=0), length (<=0), or density |
99 | 99 | /// steerings position |
100 | 100 | /// \param[in] _leftPos Left wheel position in radians. |
101 | 101 | /// \param[in] _rightPos Right wheel postion in radians. |
102 | /// \param[in] _time Current time point. | |
102 | 103 | /// \return True if the odometry is actually updated. |
103 | 104 | public: bool Update(const Angle &_leftPos, const Angle &_rightPos, |
104 | 105 | const clock::time_point &_time); |
77 | 77 | } |
78 | 78 | |
79 | 79 | // Documentation Inherited. |
80 | public: virtual void Fc(double _fc, double _fs) | |
80 | public: virtual void Fc(double _fc, double _fs) override | |
81 | 81 | { |
82 | 82 | b1 = exp(-2.0 * IGN_PI * _fc / _fs); |
83 | 83 | a0 = 1.0 - b1; |
84 | 84 | } |
85 | 85 | |
86 | 86 | /// \brief Update the filter's output. |
87 | /// \paran[in] _x Input value. | |
87 | /// \param[in] _x Input value. | |
88 | 88 | /// \return The filter's current output. |
89 | 89 | public: const T& Process(const T &_x) |
90 | 90 | { |
119 | 119 | } |
120 | 120 | |
121 | 121 | /// \brief Update the filter's output. |
122 | /// \paran[in] _x Input value. | |
122 | /// \param[in] _x Input value. | |
123 | 123 | /// \return The filter's current output. |
124 | 124 | public: const math::Quaterniond& Process( |
125 | 125 | const math::Quaterniond &_x) |
167 | 167 | } |
168 | 168 | |
169 | 169 | // Documentation Inherited. |
170 | public: void Fc(double _fc, double _fs) | |
170 | public: void Fc(double _fc, double _fs) override | |
171 | 171 | { |
172 | 172 | this->Fc(_fc, _fs, 0.5); |
173 | 173 | } |
190 | 190 | |
191 | 191 | /// \brief Set the current filter's output. |
192 | 192 | /// \param[in] _val New filter's output. |
193 | public: virtual void Set(const T &_val) | |
193 | public: virtual void Set(const T &_val) override | |
194 | 194 | { |
195 | 195 | this->y0 = this->y1 = this->y2 = this->x1 = this->x2 = _val; |
196 | 196 | } |
168 | 168 | public: void SetPose(const Pose3d &_pose); |
169 | 169 | |
170 | 170 | /// \brief Assignment operator. Set this frustum to the parameter. |
171 | /// \param[in] _b Frustum to copy | |
171 | /// \param[in] _f Frustum to copy | |
172 | 172 | /// \return The new frustum. |
173 | 173 | public: Frustum &operator=(const Frustum &_f); |
174 | 174 |
0 | /* | |
1 | * Copyright (C) 2020 Open Source Robotics Foundation | |
2 | * | |
3 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
4 | * you may not use this file except in compliance with the License. | |
5 | * You may obtain a copy of the License at | |
6 | * | |
7 | * http://www.apache.org/licenses/LICENSE-2.0 | |
8 | * | |
9 | * Unless required by applicable law or agreed to in writing, software | |
10 | * distributed under the License is distributed on an "AS IS" BASIS, | |
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 | * See the License for the specific language governing permissions and | |
13 | * limitations under the License. | |
14 | * | |
15 | */ | |
16 | #ifndef IGNITION_MATH_GAUSSMARKOVPROCESS_HH_ | |
17 | #define IGNITION_MATH_GAUSSMARKOVPROCESS_HH_ | |
18 | ||
19 | #include <chrono> | |
20 | #include <memory> | |
21 | #include <ignition/math/Export.hh> | |
22 | #include <ignition/math/config.hh> | |
23 | ||
24 | namespace ignition | |
25 | { | |
26 | namespace math | |
27 | { | |
28 | // Use a steady clock | |
29 | using clock = std::chrono::steady_clock; | |
30 | ||
31 | // Inline bracket to help doxygen filtering. | |
32 | inline namespace IGNITION_MATH_VERSION_NAMESPACE { | |
33 | // | |
34 | // Forward declarations. | |
35 | class GaussMarkovProcessPrivate; | |
36 | ||
37 | /** \class GaussMarkovProcess GaussMarkovProcess.hh\ | |
38 | * ignition/math/GaussMarkovProcess.hh | |
39 | **/ | |
40 | /// \brief Implementation of a stationary gauss-markov process, also | |
41 | /// known as a Ornstein Ulenbeck process. | |
42 | /// | |
43 | /// See the Update(const clock::duration &) for details on the forumla | |
44 | /// used to update the process. | |
45 | /// | |
46 | /// ## Example usage | |
47 | /// | |
48 | /// \snippet examples/gauss_markov_process_example.cc complete | |
49 | class IGNITION_MATH_VISIBLE GaussMarkovProcess | |
50 | { | |
51 | // Default constructor. This sets all the parameters to zero. | |
52 | public: GaussMarkovProcess(); | |
53 | ||
54 | /// \brief Create a process with the provided process parameters. | |
55 | /// This will also call Set(), and in turn Reset(). | |
56 | /// \param[in] _start The start value of the process. | |
57 | /// \param[in] _theta The theta (\f$\theta\f$) parameter. A value of | |
58 | /// zero will be used if this parameter is negative. | |
59 | /// \param[in] _mu The mu (\f$\mu\f$) parameter. | |
60 | /// \param[in] _sigma The sigma (\f$\sigma\f$) parameter. A value of | |
61 | /// zero will be used if this parameter is negative. | |
62 | /// \sa Update(const clock::duration &) | |
63 | public: GaussMarkovProcess(double _start, double _theta, double _mu, | |
64 | double _sigma); | |
65 | ||
66 | /// \brief Destructor. | |
67 | public: ~GaussMarkovProcess(); | |
68 | ||
69 | /// \brief Set the process parameters. This will also call Reset(). | |
70 | /// \param[in] _start The start value of the process. | |
71 | /// \param[in] _theta The theta (\f$\theta\f$) parameter. | |
72 | /// \param[in] _mu The mu (\f$\mu\f$) parameter. | |
73 | /// \param[in] _sigma The sigma (\f$\sigma\f$) parameter. | |
74 | /// \sa Update(const clock::duration &) | |
75 | public: void Set(double _start, double _theta, double _mu, double _sigma); | |
76 | ||
77 | /// \brief Get the start value. | |
78 | /// \return The start value. | |
79 | /// \sa Set(double, double, double, double) | |
80 | public: double Start() const; | |
81 | ||
82 | /// \brief Get the current process value. | |
83 | /// \return The value of the process. | |
84 | public: double Value() const; | |
85 | ||
86 | /// \brief Get the theta (\f$\theta\f$) value. | |
87 | /// \return The theta value. | |
88 | /// \sa Set(double, double, double, double) | |
89 | public: double Theta() const; | |
90 | ||
91 | /// \brief Get the mu (\f$\mu\f$) value. | |
92 | /// \return The mu value. | |
93 | /// \sa Set(double, double, double, double) | |
94 | public: double Mu() const; | |
95 | ||
96 | /// \brief Get the sigma (\f$\sigma\f$) value. | |
97 | /// \return The sigma value. | |
98 | /// \sa Set(double, double, double, double) | |
99 | public: double Sigma() const; | |
100 | ||
101 | /// \brief Reset the process. This will set the current process value | |
102 | /// to the start value. | |
103 | public: void Reset(); | |
104 | ||
105 | /// \brief Update the process and get the new value. | |
106 | /// | |
107 | /// The following equation is computed: | |
108 | /// | |
109 | /// \f$x_{t+1} += \theta * (\mu - x_t) * dt + \sigma * dW_t\f$ | |
110 | /// | |
111 | /// where | |
112 | /// | |
113 | /// * \f$\theta, \mu, \sigma\f$ are parameters specified by the | |
114 | /// user. In order, the parameters are theta, mu, and sigma. Theta | |
115 | /// and sigma must be greater than or equal to zero. You can think | |
116 | /// of mu as representing the mean or equilibrium value, sigma as the | |
117 | /// degree of volatility, and theta as the rate by which changes | |
118 | /// dissipate and revert towards the mean. | |
119 | /// * \f$dt\f$ is the time step in seconds. | |
120 | /// * \f$dW_t\f$ is a random number drawm from a normal distribution | |
121 | /// with mean of zero and variance of 1. | |
122 | /// * \f$x_t\f$ is the current value of the Gauss-Markov process | |
123 | /// * \f$x_{t+1}\f$ is the new value of the Gauss-Markvov process | |
124 | /// | |
125 | /// See also: https://en.wikipedia.org/wiki/Ornstein%E2%80%93Uhlenbeck_process | |
126 | /// | |
127 | /// This implementation include a drift parameter, mu. In financial | |
128 | /// mathematics, this is known as a Vasicek model. | |
129 | /// | |
130 | /// \param[in] _dt Length of the timestep after which a new sample | |
131 | /// should be taken. | |
132 | /// \return The new value of this process. | |
133 | public: double Update(const clock::duration &_dt); | |
134 | ||
135 | public: double Update(double _dt); | |
136 | ||
137 | #ifdef _WIN32 | |
138 | // Disable warning C4251 which is triggered by | |
139 | // std::unique_ptr | |
140 | #pragma warning(push) | |
141 | #pragma warning(disable: 4251) | |
142 | #endif | |
143 | /// \brief Private data pointer. | |
144 | private: std::unique_ptr<GaussMarkovProcessPrivate> dataPtr; | |
145 | #ifdef _WIN32 | |
146 | #pragma warning(pop) | |
147 | #endif | |
148 | }; | |
149 | } | |
150 | } | |
151 | } | |
152 | #endif |
16 | 16 | #ifndef IGNITION_MATH_FUNCTIONS_HH_ |
17 | 17 | #define IGNITION_MATH_FUNCTIONS_HH_ |
18 | 18 | |
19 | #include <algorithm> | |
19 | 20 | #include <chrono> |
20 | 21 | #include <cmath> |
21 | #include <algorithm> | |
22 | #include <cstdint> | |
23 | #include <iomanip> | |
24 | #include <iostream> | |
22 | 25 | #include <limits> |
26 | #include <regex> | |
27 | #include <sstream> | |
23 | 28 | #include <string> |
24 | #include <iostream> | |
25 | #include <vector> | |
26 | 29 | #include <tuple> |
27 | 30 | #include <utility> |
28 | #include <cstdint> | |
31 | #include <vector> | |
29 | 32 | |
30 | 33 | #include <ignition/math/config.hh> |
31 | 34 | #include "ignition/math/Export.hh" |
726 | 729 | } |
727 | 730 | } |
728 | 731 | |
732 | /// \brief Convert a std::chrono::steady_clock::time_point to a seconds and | |
733 | /// nanoseconds pair. | |
734 | /// \param[in] _time The time point to convert. | |
735 | /// \return A pair where the first element is the number of seconds and | |
736 | /// the second is the number of nanoseconds. | |
737 | inline std::pair<int64_t, int64_t> timePointToSecNsec( | |
738 | const std::chrono::steady_clock::time_point &_time) | |
739 | { | |
740 | auto now_ns = std::chrono::duration_cast<std::chrono::nanoseconds>( | |
741 | _time.time_since_epoch()); | |
742 | auto now_s = std::chrono::duration_cast<std::chrono::seconds>( | |
743 | _time.time_since_epoch()); | |
744 | int64_t seconds = now_s.count(); | |
745 | int64_t nanoseconds = std::chrono::duration_cast | |
746 | <std::chrono::nanoseconds>(now_ns - now_s).count(); | |
747 | return {seconds, nanoseconds}; | |
748 | } | |
749 | ||
750 | /// \brief Convert seconds and nanoseconds to | |
751 | /// std::chrono::steady_clock::time_point. | |
752 | /// \param[in] _sec The seconds to convert. | |
753 | /// \param[in] _nanosec The nanoseconds to convert. | |
754 | /// \return A std::chrono::steady_clock::time_point based on the number of | |
755 | /// seconds and the number of nanoseconds. | |
756 | inline std::chrono::steady_clock::time_point secNsecToTimePoint( | |
757 | const uint64_t &_sec, const uint64_t &_nanosec) | |
758 | { | |
759 | auto duration = std::chrono::seconds(_sec) + std::chrono::nanoseconds( | |
760 | _nanosec); | |
761 | std::chrono::steady_clock::time_point result; | |
762 | using std::chrono::duration_cast; | |
763 | result += duration_cast<std::chrono::steady_clock::duration>(duration); | |
764 | return result; | |
765 | } | |
766 | ||
767 | /// \brief Convert seconds and nanoseconds to | |
768 | /// std::chrono::steady_clock::duration. | |
769 | /// \param[in] _sec The seconds to convert. | |
770 | /// \param[in] _nanosec The nanoseconds to convert. | |
771 | /// \return A std::chrono::steady_clock::duration based on the number of | |
772 | /// seconds and the number of nanoseconds. | |
773 | inline std::chrono::steady_clock::duration secNsecToDuration( | |
774 | const uint64_t &_sec, const uint64_t &_nanosec) | |
775 | { | |
776 | return std::chrono::seconds(_sec) + std::chrono::nanoseconds( | |
777 | _nanosec); | |
778 | } | |
779 | ||
729 | 780 | /// \brief Convert a std::chrono::steady_clock::duration to a seconds and |
730 | 781 | /// nanoseconds pair. |
731 | 782 | /// \param[in] _dur The duration to convert. |
737 | 788 | auto s = std::chrono::duration_cast<std::chrono::seconds>(_dur); |
738 | 789 | auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(_dur-s); |
739 | 790 | return {s.count(), ns.count()}; |
791 | } | |
792 | ||
793 | // TODO(anyone): Replace this with std::chrono::days. | |
794 | /// This will exist in C++-20 | |
795 | typedef std::chrono::duration<uint64_t, std::ratio<86400>> days; | |
796 | ||
797 | /// \brief break down durations | |
798 | /// NOTE: the template arguments must be properly ordered according | |
799 | /// to magnitude and there can be no duplicates. | |
800 | /// This function uses the braces initializer to split all the templated | |
801 | /// duration. The initializer will be called recursievely due the `...` | |
802 | /// \param[in] d Duration to break down | |
803 | /// \return A tuple based on the durations specified | |
804 | template<class...Durations, class DurationIn> | |
805 | std::tuple<Durations...> breakDownDurations(DurationIn d) { | |
806 | std::tuple<Durations...> retval; | |
807 | using discard = int[]; | |
808 | (void)discard{0, (void(( | |
809 | (std::get<Durations>(retval) = | |
810 | std::chrono::duration_cast<Durations>(d)), | |
811 | (d -= std::chrono::duration_cast<DurationIn>( | |
812 | std::get<Durations>(retval))))), 0)...}; | |
813 | return retval; | |
814 | } | |
815 | ||
816 | /// \brief Convert a std::chrono::steady_clock::time_point to a string | |
817 | /// \param[in] _point The std::chrono::steady_clock::time_point to convert. | |
818 | /// \return A string formatted with the time_point | |
819 | inline std::string timePointToString( | |
820 | const std::chrono::steady_clock::time_point &_point) | |
821 | { | |
822 | auto duration = _point - secNsecToTimePoint(0, 0); | |
823 | auto cleanDuration = breakDownDurations<days, | |
824 | std::chrono::hours, | |
825 | std::chrono::minutes, | |
826 | std::chrono::seconds, | |
827 | std::chrono::milliseconds>( | |
828 | duration); | |
829 | std::ostringstream output_string; | |
830 | output_string << std::setw(2) << std::setfill('0') | |
831 | << std::get<0>(cleanDuration).count() << " " | |
832 | << std::setw(2) << std::setfill('0') | |
833 | << std::get<1>(cleanDuration).count() << ":" | |
834 | << std::setw(2) << std::setfill('0') | |
835 | << std::get<2>(cleanDuration).count() << ":" | |
836 | << std::setfill('0') << std::setw(6) | |
837 | << std::fixed << std::setprecision(3) | |
838 | << std::get<3>(cleanDuration).count() + | |
839 | std::get<4>(cleanDuration).count()/1000.0; | |
840 | return output_string.str(); | |
841 | } | |
842 | ||
843 | /// \brief Convert a std::chrono::steady_clock::duration to a string | |
844 | /// \param[in] _duration The std::chrono::steady_clock::duration to convert. | |
845 | /// \return A string formatted with the duration | |
846 | inline std::string durationToString( | |
847 | const std::chrono::steady_clock::duration &_duration) | |
848 | { | |
849 | auto cleanDuration = breakDownDurations<days, | |
850 | std::chrono::hours, | |
851 | std::chrono::minutes, | |
852 | std::chrono::seconds, | |
853 | std::chrono::milliseconds>( | |
854 | _duration); | |
855 | std::ostringstream outputString; | |
856 | outputString << std::setw(2) << std::setfill('0') | |
857 | << std::get<0>(cleanDuration).count() << " " | |
858 | << std::setw(2) << std::setfill('0') | |
859 | << std::get<1>(cleanDuration).count() << ":" | |
860 | << std::setw(2) << std::setfill('0') | |
861 | << std::get<2>(cleanDuration).count() << ":" | |
862 | << std::setfill('0') << std::setw(6) | |
863 | << std::fixed << std::setprecision(3) | |
864 | << std::get<3>(cleanDuration).count() + | |
865 | std::get<4>(cleanDuration).count()/1000.0; | |
866 | return outputString.str(); | |
867 | } | |
868 | ||
869 | // The following regex takes a time string in the general format of | |
870 | // "dd hh:mm:ss.nnn" where n is milliseconds, if just one number is | |
871 | // provided, it is assumed to be seconds | |
872 | static const std::regex time_regex( | |
873 | "^([0-9]+ ){0,1}" // day: | |
874 | // Any positive integer | |
875 | ||
876 | "(?:([1-9]:|[0-1][0-9]:|2[0-3]:){0,1}" // hour: | |
877 | // 1 - 9: | |
878 | // 01 - 19: | |
879 | // 20 - 23: | |
880 | ||
881 | "([0-9]:|[0-5][0-9]:)){0,1}" // minute: | |
882 | // 0 - 9: | |
883 | // 00 - 59: | |
884 | ||
885 | "(?:([0-9]|[0-5][0-9]){0,1}" // second: | |
886 | // 0 - 9 | |
887 | // 00 - 59 | |
888 | ||
889 | "(\\.[0-9]{1,3}){0,1})$"); // millisecond: | |
890 | // .0 - .9 | |
891 | // .00 - .99 | |
892 | // .000 - 0.999 | |
893 | ||
894 | ||
895 | /// \brief Split a std::chrono::steady_clock::duration to a string | |
896 | /// \param[in] _timeString The string to convert in general format | |
897 | /// \param[out] numberDays number of days in the string | |
898 | /// \param[out] numberHours number of hours in the string | |
899 | /// \param[out] numberMinutes number of minutes in the string | |
900 | /// \param[out] numberSeconds number of seconds in the string | |
901 | /// \param[out] numberMilliseconds number of milliseconds in the string | |
902 | /// \return True if the regex was able to split the string otherwise False | |
903 | inline bool splitTimeBasedOnTimeRegex( | |
904 | const std::string &_timeString, | |
905 | uint64_t & numberDays, uint64_t & numberHours, | |
906 | uint64_t & numberMinutes, uint64_t & numberSeconds, | |
907 | uint64_t & numberMilliseconds) | |
908 | { | |
909 | std::smatch matches; | |
910 | ||
911 | // `matches` should always be a size of 6 as there are 6 matching | |
912 | // groups in the regex. | |
913 | // 1. The whole regex | |
914 | // 2. The days | |
915 | // 3. The hours | |
916 | // 4. The minutes | |
917 | // 5. The seconds | |
918 | // 6. The milliseconds | |
919 | // We can also index them as such below. | |
920 | // Note that the space will remain in the day match, the colon | |
921 | // will remain in the hour and minute matches, and the period will | |
922 | // remain in the millisecond match | |
923 | if (!std::regex_search(_timeString, matches, time_regex) || | |
924 | matches.size() != 6) | |
925 | return false; | |
926 | ||
927 | std::string dayString = matches[1]; | |
928 | std::string hourString = matches[2]; | |
929 | std::string minuteString = matches[3]; | |
930 | std::string secondString = matches[4]; | |
931 | std::string millisecondString = matches[5]; | |
932 | ||
933 | // Days are the only unbounded number, so check first to see if stoi | |
934 | // runs successfully | |
935 | if (!dayString.empty()) | |
936 | { | |
937 | // Erase the space | |
938 | dayString.erase(dayString.length() - 1); | |
939 | try | |
940 | { | |
941 | numberDays = std::stoi(dayString); | |
942 | } | |
943 | catch (const std::out_of_range &) | |
944 | { | |
945 | return false; | |
946 | } | |
947 | } | |
948 | ||
949 | if (!hourString.empty()) | |
950 | { | |
951 | // Erase the colon | |
952 | hourString.erase(hourString.length() - 1); | |
953 | numberHours = std::stoi(hourString); | |
954 | } | |
955 | ||
956 | if (!minuteString.empty()) | |
957 | { | |
958 | // Erase the colon | |
959 | minuteString.erase(minuteString.length() - 1); | |
960 | numberMinutes = std::stoi(minuteString); | |
961 | } | |
962 | ||
963 | if (!secondString.empty()) | |
964 | { | |
965 | numberSeconds = std::stoi(secondString); | |
966 | } | |
967 | ||
968 | if (!millisecondString.empty()) | |
969 | { | |
970 | // Erase the period | |
971 | millisecondString.erase(0, 1); | |
972 | ||
973 | // Multiplier because "4" = 400 ms, "04" = 40 ms, and "004" = 4 ms | |
974 | numberMilliseconds = std::stoi(millisecondString) * | |
975 | static_cast<uint64_t>(1000 / pow(10, millisecondString.length())); | |
976 | } | |
977 | return true; | |
978 | } | |
979 | ||
980 | /// \brief Convert a string to a std::chrono::steady_clock::duration | |
981 | /// \param[in] _timeString The string to convert in general format | |
982 | /// "dd hh:mm:ss.nnn" where n is millisecond value | |
983 | /// \return A std::chrono::steady_clock::duration containing the | |
984 | /// string's time value. If it isn't possible to convert, the duration will | |
985 | /// be zero. | |
986 | inline std::chrono::steady_clock::duration stringToDuration( | |
987 | const std::string &_timeString) | |
988 | { | |
989 | using namespace std::chrono_literals; | |
990 | std::chrono::steady_clock::duration duration{ | |
991 | std::chrono::steady_clock::duration::zero()}; | |
992 | ||
993 | if (_timeString.empty()) | |
994 | return duration; | |
995 | ||
996 | uint64_t numberDays = 0; | |
997 | uint64_t numberHours = 0; | |
998 | uint64_t numberMinutes = 0; | |
999 | uint64_t numberSeconds = 0; | |
1000 | uint64_t numberMilliseconds = 0; | |
1001 | ||
1002 | if (!splitTimeBasedOnTimeRegex(_timeString, numberDays, numberHours, | |
1003 | numberMinutes, numberSeconds, | |
1004 | numberMilliseconds)) | |
1005 | { | |
1006 | return duration; | |
1007 | } | |
1008 | ||
1009 | // TODO(anyone): Replace below day conversion with std::chrono::days. | |
1010 | /// This will exist in C++-20 | |
1011 | duration = std::chrono::steady_clock::duration::zero(); | |
1012 | auto delta = std::chrono::milliseconds(numberMilliseconds) + | |
1013 | std::chrono::seconds(numberSeconds) + | |
1014 | std::chrono::minutes(numberMinutes) + | |
1015 | std::chrono::hours(numberHours) + | |
1016 | std::chrono::hours(24 * numberDays); | |
1017 | duration += delta; | |
1018 | ||
1019 | return duration; | |
1020 | } | |
1021 | ||
1022 | /// \brief Convert a string to a std::chrono::steady_clock::time_point | |
1023 | /// \param[in] _timeString The string to convert in general format | |
1024 | /// "dd hh:mm:ss.nnn" where n is millisecond value | |
1025 | /// \return A std::chrono::steady_clock::time_point containing the | |
1026 | /// string's time value. If it isn't possible to convert, the time will | |
1027 | /// be negative 1 second. | |
1028 | inline std::chrono::steady_clock::time_point stringToTimePoint( | |
1029 | const std::string &_timeString) | |
1030 | { | |
1031 | using namespace std::chrono_literals; | |
1032 | std::chrono::steady_clock::time_point timePoint{-1s}; | |
1033 | ||
1034 | if (_timeString.empty()) | |
1035 | return timePoint; | |
1036 | ||
1037 | uint64_t numberDays = 0; | |
1038 | uint64_t numberHours = 0; | |
1039 | uint64_t numberMinutes = 0; | |
1040 | uint64_t numberSeconds = 0; | |
1041 | uint64_t numberMilliseconds = 0; | |
1042 | ||
1043 | if (!splitTimeBasedOnTimeRegex(_timeString, numberDays, numberHours, | |
1044 | numberMinutes, numberSeconds, | |
1045 | numberMilliseconds)) | |
1046 | { | |
1047 | return timePoint; | |
1048 | } | |
1049 | ||
1050 | // TODO(anyone): Replace below day conversion with std::chrono::days. | |
1051 | /// This will exist in C++-20 | |
1052 | timePoint = math::secNsecToTimePoint(0, 0); | |
1053 | auto duration = std::chrono::milliseconds(numberMilliseconds) + | |
1054 | std::chrono::seconds(numberSeconds) + | |
1055 | std::chrono::minutes(numberMinutes) + | |
1056 | std::chrono::hours(numberHours) + | |
1057 | std::chrono::hours(24 * numberDays); | |
1058 | timePoint += duration; | |
1059 | ||
1060 | return timePoint; | |
740 | 1061 | } |
741 | 1062 | |
742 | 1063 | // Degrade precision on Windows, which cannot handle 'long double' |
237 | 237 | ixxyyzz.X() += m1 * (std::pow(dc[1], 2) + std::pow(dc[2], 2)); |
238 | 238 | ixxyyzz.Y() += m1 * (std::pow(dc[2], 2) + std::pow(dc[0], 2)); |
239 | 239 | ixxyyzz.Z() += m1 * (std::pow(dc[0], 2) + std::pow(dc[1], 2)); |
240 | ixxyyzz.X() -= m1 * dc[0] * dc[1]; | |
241 | ixxyyzz.Y() -= m1 * dc[0] * dc[2]; | |
242 | ixxyyzz.Z() -= m1 * dc[1] * dc[2]; | |
240 | ixyxzyz.X() -= m1 * dc[0] * dc[1]; | |
241 | ixyxzyz.Y() -= m1 * dc[0] * dc[2]; | |
242 | ixyxzyz.Z() -= m1 * dc[1] * dc[2]; | |
243 | 243 | } |
244 | 244 | { |
245 | 245 | auto dc = com2 - com; |
246 | 246 | ixxyyzz.X() += m2 * (std::pow(dc[1], 2) + std::pow(dc[2], 2)); |
247 | 247 | ixxyyzz.Y() += m2 * (std::pow(dc[2], 2) + std::pow(dc[0], 2)); |
248 | 248 | ixxyyzz.Z() += m2 * (std::pow(dc[0], 2) + std::pow(dc[1], 2)); |
249 | ixxyyzz.X() -= m2 * dc[0] * dc[1]; | |
250 | ixxyyzz.Y() -= m2 * dc[0] * dc[2]; | |
251 | ixxyyzz.Z() -= m2 * dc[1] * dc[2]; | |
249 | ixyxzyz.X() -= m2 * dc[0] * dc[1]; | |
250 | ixyxzyz.Y() -= m2 * dc[0] * dc[2]; | |
251 | ixyxzyz.Z() -= m2 * dc[1] * dc[2]; | |
252 | 252 | } |
253 | 253 | this->massMatrix = MassMatrix3<T>(mass, ixxyyzz, ixyxzyz); |
254 | 254 | this->pose = Pose3<T>(com, Quaternion<T>::Identity); |
297 | 297 | |
298 | 298 | /// \brief Stream extraction operator |
299 | 299 | /// \param[in] _out output stream |
300 | /// \param[in] _pt Line2 to output | |
300 | /// \param[in] _line Line2 to output | |
301 | 301 | /// \return The stream |
302 | 302 | public: friend std::ostream &operator<<( |
303 | 303 | std::ostream &_out, const Line2<T> &_line) |
153 | 153 | /// point of this line and the closest point in the provided line. |
154 | 154 | /// \param[in] _line Line to compare against this. |
155 | 155 | /// \param[out] _result The shortest line between _line and this. |
156 | /// \param[in] _epsilon Error tolerance. | |
156 | 157 | /// \return True if a solution was found. False if a solution is not |
157 | 158 | /// possible. |
158 | 159 | public: bool Distance(const Line3<T> &_line, Line3<T> &_result, |
59 | 59 | {} |
60 | 60 | |
61 | 61 | /// \brief Copy constructor. |
62 | /// \param[in] _massMatrix MassMatrix3 element to copy | |
62 | /// \param[in] _m MassMatrix3 element to copy | |
63 | 63 | public: MassMatrix3(const MassMatrix3<T> &_m) |
64 | 64 | : mass(_m.Mass()), Ixxyyzz(_m.DiagonalMoments()), |
65 | 65 | Ixyxzyz(_m.OffDiagonalMoments()) |
173 | 173 | /// \brief Set the off-diagonal moments of inertia (Ixy, Ixz, Iyz). |
174 | 174 | /// \param[in] _ixyxzyz off-diagonal moments of inertia |
175 | 175 | /// \return True if the MassMatrix3 is valid. |
176 | /// \deprecated See bool SetOffDiagonalMoments(const Vector3<T> &_ixyxzyz) | |
177 | 176 | public: bool SetOffDiagonalMoments(const Vector3<T> &_ixyxzyz) |
178 | 177 | { |
179 | 178 | this->Ixyxzyz = _ixyxzyz; |
399 | 398 | /// \brief Sets Moments of Inertia (MOI) from a Matrix3. |
400 | 399 | /// Symmetric component of input matrix is used by averaging |
401 | 400 | /// off-axis terms. |
402 | /// \param[in] Moments of Inertia as a Matrix3 | |
401 | /// \param[in] _moi Moments of Inertia as a Matrix3 | |
403 | 402 | /// \return True if the MassMatrix3 is valid. |
404 | 403 | /// \deprecated See SetMoi(const Matrix3<T> &_moi) |
405 | 404 | public: bool IGN_DEPRECATED(5.0) MOI(const Matrix3<T> &_moi) |
410 | 409 | /// \brief Sets Moments of Inertia (MOI) from a Matrix3. |
411 | 410 | /// Symmetric component of input matrix is used by averaging |
412 | 411 | /// off-axis terms. |
413 | /// \param[in] Moments of Inertia as a Matrix3 | |
412 | /// \param[in] _moi Moments of Inertia as a Matrix3 | |
414 | 413 | /// \return True if the MassMatrix3 is valid. |
415 | 414 | public: bool SetMoi(const Matrix3<T> &_moi) |
416 | 415 | { |
984 | 983 | + std::pow(cos(phi11c.Radian()) - cos(phi12c.Radian()), 2); |
985 | 984 | if (errc < err) |
986 | 985 | { |
987 | err = errc; | |
988 | 986 | phi1 = phi11c.Radian(); |
989 | 987 | signsPhi23.Set(-1, -1); |
990 | 988 | } |
1070 | 1068 | const Quaternion<T> &_rot = Quaternion<T>::Identity) |
1071 | 1069 | { |
1072 | 1070 | // Check that _mass and _size are strictly positive |
1073 | // and that quatenion is valid | |
1071 | // and that quaternion is valid | |
1074 | 1072 | if (_mass <= 0 || _size.Min() <= 0 || _rot == Quaternion<T>::Zero) |
1075 | 1073 | { |
1076 | 1074 | return false; |
1088 | 1086 | const Quaternion<T> &_rot = Quaternion<T>::Identity) |
1089 | 1087 | { |
1090 | 1088 | // Check that _mass and _size are strictly positive |
1091 | // and that quatenion is valid | |
1089 | // and that quaternion is valid | |
1092 | 1090 | if (this->Mass() <= 0 || _size.Min() <= 0 || |
1093 | 1091 | _rot == Quaternion<T>::Zero) |
1094 | 1092 | { |
1121 | 1119 | const Quaternion<T> &_rot = Quaternion<T>::Identity) |
1122 | 1120 | { |
1123 | 1121 | // Check that density, _radius and _length are strictly positive |
1124 | // and that quatenion is valid | |
1122 | // and that quaternion is valid | |
1125 | 1123 | if (_mat.Density() <= 0 || _length <= 0 || _radius <= 0 || |
1126 | 1124 | _rot == Quaternion<T>::Zero) |
1127 | 1125 | { |
1145 | 1143 | const Quaternion<T> &_rot = Quaternion<T>::Identity) |
1146 | 1144 | { |
1147 | 1145 | // Check that _mass, _radius and _length are strictly positive |
1148 | // and that quatenion is valid | |
1146 | // and that quaternion is valid | |
1149 | 1147 | if (_mass <= 0 || _length <= 0 || _radius <= 0 || |
1150 | 1148 | _rot == Quaternion<T>::Zero) |
1151 | 1149 | { |
1166 | 1164 | const Quaternion<T> &_rot) |
1167 | 1165 | { |
1168 | 1166 | // Check that _mass and _size are strictly positive |
1169 | // and that quatenion is valid | |
1167 | // and that quaternion is valid | |
1170 | 1168 | if (this->Mass() <= 0 || _length <= 0 || _radius <= 0 || |
1171 | 1169 | _rot == Quaternion<T>::Zero) |
1172 | 1170 | { |
40 | 40 | /// enum. |
41 | 41 | /// |
42 | 42 | /// This class will replace the |
43 | /// [MaterialDensity class](https://bitbucket.org/ignitionrobotics/ign-common/src/ign-common1/include/ignition/common/MaterialDensity.hh) | |
43 | /// [MaterialDensity class](https://github.com/ignitionrobotics/ign-common/blob/ign-common1/include/ignition/common/MaterialDensity.hh) | |
44 | 44 | /// found in the Ignition Common library, which was at version 1 at the |
45 | 45 | /// time of this writing. |
46 | 46 | /// |
503 | 503 | |
504 | 504 | return _out; |
505 | 505 | } |
506 | ||
506 | 507 | /// \brief Stream extraction operator |
507 | /// \param _in input stream | |
508 | /// \param _pt Matrix3 to read values into | |
508 | /// \param[in,out] _in input stream | |
509 | /// \param[out] _m Matrix3 to read values into | |
509 | 510 | /// \return the stream |
510 | 511 | public: friend std::istream &operator>>( |
511 | 512 | std::istream &_in, ignition::math::Matrix3<T> &_m) |
621 | 621 | |
622 | 622 | /// \brief Multiplication assignment operator. This matrix will |
623 | 623 | /// become equal to this * _m2. |
624 | /// \param _mat Incoming matrix. | |
624 | /// \param[in] _m2 Incoming matrix. | |
625 | 625 | /// \return This matrix * _mat. |
626 | 626 | public: Matrix4<T> operator*=(const Matrix4<T> &_m2) |
627 | 627 | { |
630 | 630 | } |
631 | 631 | |
632 | 632 | /// \brief Multiplication operator |
633 | /// \param _mat Incoming matrix | |
633 | /// \param[in] _m2 Incoming matrix | |
634 | 634 | /// \return This matrix * _mat |
635 | 635 | public: Matrix4<T> operator*(const Matrix4<T> &_m2) const |
636 | 636 | { |
826 | 826 | } |
827 | 827 | |
828 | 828 | /// \brief Stream extraction operator |
829 | /// \param _in input stream | |
830 | /// \param _pt Matrix4<T> to read values into | |
829 | /// \param[in,out] _in input stream | |
830 | /// \param[out] _m Matrix4<T> to read values into | |
831 | 831 | /// \return the stream |
832 | 832 | public: friend std::istream &operator>>( |
833 | 833 | std::istream &_in, ignition::math::Matrix4<T> &_m) |
52 | 52 | /// \brief keep track of number of elements |
53 | 53 | public: unsigned int samples = 0; |
54 | 54 | }; |
55 | /// \endcond | |
56 | 55 | |
57 | 56 | ////////////////////////////////////////////////// |
58 | 57 | template<typename T> |
63 | 62 | this->valIter = this->valHistory.begin(); |
64 | 63 | this->sum = T(); |
65 | 64 | } |
65 | /// \endcond | |
66 | 66 | |
67 | 67 | /// \brief Base class for MovingWindowFilter. This replaces the |
68 | 68 | /// version of MovingWindowFilter in the Ignition Common library. |
212 | 212 | return this->p != _pose.p || this->q != _pose.q; |
213 | 213 | } |
214 | 214 | |
215 | /// \brief Multiplication operator | |
216 | /// \param[in] _pose the other pose | |
217 | /// \return itself | |
215 | /// \brief Multiplication operator. | |
216 | /// Given X_OP (frame P relative to O) and X_PQ (frame Q relative to P) | |
217 | /// then X_OQ = X_OP * X_PQ (frame Q relative to O). | |
218 | /// \param[in] _pose The pose to multiply by. | |
219 | /// \return The resulting pose. | |
218 | 220 | public: Pose3<T> operator*(const Pose3<T> &_pose) const |
219 | 221 | { |
220 | 222 | return Pose3<T>(_pose.CoordPositionAdd(*this), this->q * _pose.q); |
230 | 232 | return *this; |
231 | 233 | } |
232 | 234 | |
233 | /// \brief Equal operator | |
235 | /// \brief Assignment operator | |
234 | 236 | /// \param[in] _pose Pose3<T> to copy |
235 | 237 | public: Pose3<T> &operator=(const Pose3<T> &_pose) |
236 | 238 | { |
328 | 330 | } |
329 | 331 | |
330 | 332 | /// \brief Rotate vector part of a pose about the origin |
331 | /// \param[in] _rot rotation | |
333 | /// \param[in] _q rotation | |
332 | 334 | /// \return the rotated pose |
333 | 335 | public: Pose3<T> RotatePositionAboutOrigin(const Quaternion<T> &_q) const |
334 | 336 | { |
367 | 369 | return this->p; |
368 | 370 | } |
369 | 371 | |
372 | /// \brief Get the X value of the position. | |
373 | /// \return Value X of the origin of the pose. | |
374 | /// \note The return is made by value since | |
375 | /// Vector3<T>.X() is already a reference. | |
376 | public: inline const T X() const | |
377 | { | |
378 | return this->p.X(); | |
379 | } | |
380 | ||
381 | /// \brief Set X value of the position. | |
382 | public: inline void SetX(T x) | |
383 | { | |
384 | this->p.X() = x; | |
385 | } | |
386 | ||
387 | /// \brief Get the Y value of the position. | |
388 | /// \return Value Y of the origin of the pose. | |
389 | /// \note The return is made by value since | |
390 | /// Vector3<T>.Y() is already a reference. | |
391 | public: inline const T Y() const | |
392 | { | |
393 | return this->p.Y(); | |
394 | } | |
395 | ||
396 | /// \brief Set the Y value of the position. | |
397 | public: inline void SetY(T y) | |
398 | { | |
399 | this->p.Y() = y; | |
400 | } | |
401 | ||
402 | /// \brief Get the Z value of the position. | |
403 | /// \return Value Z of the origin of the pose. | |
404 | /// \note The return is made by value since | |
405 | /// Vector3<T>.Z() is already a reference. | |
406 | public: inline const T Z() const | |
407 | { | |
408 | return this->p.Z(); | |
409 | } | |
410 | ||
411 | /// \brief Set the Z value of the position. | |
412 | public: inline void SetZ(T z) | |
413 | { | |
414 | this->p.Z() = z; | |
415 | } | |
416 | ||
370 | 417 | /// \brief Get the rotation. |
371 | 418 | /// \return Quaternion representation of the rotation. |
372 | 419 | public: inline const Quaternion<T> &Rot() const |
379 | 426 | public: inline Quaternion<T> &Rot() |
380 | 427 | { |
381 | 428 | return this->q; |
429 | } | |
430 | ||
431 | /// \brief Get the Roll value of the rotation. | |
432 | /// \return Roll value of the orientation. | |
433 | /// \note The return is made by value since | |
434 | /// Quaternion<T>.Roll() is already a reference. | |
435 | public: inline const T Roll() const | |
436 | { | |
437 | return this->q.Roll(); | |
438 | } | |
439 | ||
440 | /// \brief Get the Pitch value of the rotation. | |
441 | /// \return Pitch value of the orientation. | |
442 | /// \note The return is made by value since | |
443 | /// Quaternion<T>.Pitch() is already a reference. | |
444 | public: inline const T Pitch() const | |
445 | { | |
446 | return this->q.Pitch(); | |
447 | } | |
448 | ||
449 | /// \brief Get the Yaw value of the rotation. | |
450 | /// \return Yaw value of the orientation. | |
451 | /// \note The return is made by value since | |
452 | /// Quaternion<T>.Yaw() is already a reference. | |
453 | public: inline const T Yaw() const | |
454 | { | |
455 | return this->q.Yaw(); | |
382 | 456 | } |
383 | 457 | |
384 | 458 | /// \brief Stream insertion operator |
104 | 104 | /// \brief Destructor |
105 | 105 | public: ~Quaternion() {} |
106 | 106 | |
107 | /// \brief Equal operator | |
107 | /// \brief Assignment operator | |
108 | 108 | /// \param[in] _qt Quaternion<T> to copy |
109 | 109 | public: Quaternion<T> &operator=(const Quaternion<T> &_qt) |
110 | 110 | { |
243 | 243 | } |
244 | 244 | } |
245 | 245 | |
246 | /// \brief Gets a normalized version of this quaternion | |
247 | /// \return a normalized quaternion | |
248 | public: Quaternion<T> Normalized() const | |
249 | { | |
250 | Quaternion<T> result = *this; | |
251 | result.Normalize(); | |
252 | return result; | |
253 | } | |
254 | ||
246 | 255 | /// \brief Set the quaternion from an axis and angle |
247 | /// \param[in] _x X axis | |
248 | /// \param[in] _y Y axis | |
249 | /// \param[in] _z Z axis | |
250 | /// \param[in] _a Angle in radians | |
256 | /// \param[in] _ax X axis | |
257 | /// \param[in] _ay Y axis | |
258 | /// \param[in] _az Z axis | |
259 | /// \param[in] _aa Angle in radians | |
251 | 260 | public: void Axis(T _ax, T _ay, T _az, T _aa) |
252 | 261 | { |
253 | 262 | T l; |
283 | 292 | } |
284 | 293 | |
285 | 294 | /// \brief Set this quaternion from 4 floating numbers |
286 | /// \param[in] _u u | |
295 | /// \param[in] _w w | |
287 | 296 | /// \param[in] _x x |
288 | 297 | /// \param[in] _y y |
289 | 298 | /// \param[in] _z z |
658 | 667 | /// \brief Multiplication operator |
659 | 668 | /// \param[in] _qt Quaternion<T> for multiplication |
660 | 669 | /// \return This quaternion multiplied by the parameter |
661 | public: Quaternion<T> operator*=(const Quaternion<T> &qt) | |
662 | { | |
663 | *this = *this * qt; | |
670 | public: Quaternion<T> operator*=(const Quaternion<T> &_qt) | |
671 | { | |
672 | *this = *this * _qt; | |
664 | 673 | return *this; |
665 | 674 | } |
666 | 675 | |
838 | 847 | |
839 | 848 | /// \brief Spherical quadratic interpolation |
840 | 849 | /// given the ends and an interpolation parameter between 0 and 1 |
841 | /// \param[in] _ft the interpolation parameter | |
850 | /// \param[in] _fT the interpolation parameter | |
842 | 851 | /// \param[in] _rkP the beginning quaternion |
843 | 852 | /// \param[in] _rkA first intermediate quaternion |
844 | 853 | /// \param[in] _rkB second intermediate quaternion |
859 | 868 | |
860 | 869 | /// \brief Spherical linear interpolation between 2 quaternions, |
861 | 870 | /// given the ends and an interpolation parameter between 0 and 1 |
862 | /// \param[in] _ft the interpolation parameter | |
871 | /// \param[in] _fT the interpolation parameter | |
863 | 872 | /// \param[in] _rkP the beginning quaternion |
864 | 873 | /// \param[in] _rkQ the end quaternion |
865 | 874 | /// \param[in] _shortestPath when true, the rotation may be inverted to |
74 | 74 | /// \brief Parse a version string and set the major, minor, patch |
75 | 75 | /// numbers, and prerelease and build strings. |
76 | 76 | /// \param[in] _versionStr The version string, such as "1.2.3-pr+123" |
77 | /// \retur True on success. | |
77 | /// \return True on success. | |
78 | 78 | public: bool Parse(const std::string &_versionStr); |
79 | 79 | |
80 | 80 | /// \brief Returns the version as a string |
84 | 84 | class IGNITION_MATH_VISIBLE SignalMaximum : public SignalStatistic |
85 | 85 | { |
86 | 86 | // Documentation inherited. |
87 | public: virtual double Value() const; | |
87 | public: virtual double Value() const override; | |
88 | 88 | |
89 | 89 | /// \brief Get a short version of the name of this statistical measure. |
90 | 90 | /// \return "max" |
91 | public: virtual std::string ShortName() const; | |
92 | ||
93 | // Documentation inherited. | |
94 | public: virtual void InsertData(const double _data); | |
91 | public: virtual std::string ShortName() const override; | |
92 | ||
93 | // Documentation inherited. | |
94 | public: virtual void InsertData(const double _data) override; | |
95 | 95 | }; |
96 | 96 | /// \} |
97 | 97 | |
100 | 100 | class IGNITION_MATH_VISIBLE SignalMean : public SignalStatistic |
101 | 101 | { |
102 | 102 | // Documentation inherited. |
103 | public: virtual double Value() const; | |
103 | public: virtual double Value() const override; | |
104 | 104 | |
105 | 105 | /// \brief Get a short version of the name of this statistical measure. |
106 | 106 | /// \return "mean" |
107 | public: virtual std::string ShortName() const; | |
108 | ||
109 | // Documentation inherited. | |
110 | public: virtual void InsertData(const double _data); | |
107 | public: virtual std::string ShortName() const override; | |
108 | ||
109 | // Documentation inherited. | |
110 | public: virtual void InsertData(const double _data) override; | |
111 | 111 | }; |
112 | 112 | /// \} |
113 | 113 | |
116 | 116 | class IGNITION_MATH_VISIBLE SignalMinimum : public SignalStatistic |
117 | 117 | { |
118 | 118 | // Documentation inherited. |
119 | public: virtual double Value() const; | |
119 | public: virtual double Value() const override; | |
120 | 120 | |
121 | 121 | /// \brief Get a short version of the name of this statistical measure. |
122 | 122 | /// \return "min" |
123 | public: virtual std::string ShortName() const; | |
124 | ||
125 | // Documentation inherited. | |
126 | public: virtual void InsertData(const double _data); | |
123 | public: virtual std::string ShortName() const override; | |
124 | ||
125 | // Documentation inherited. | |
126 | public: virtual void InsertData(const double _data) override; | |
127 | 127 | }; |
128 | 128 | /// \} |
129 | 129 | |
133 | 133 | class IGNITION_MATH_VISIBLE SignalRootMeanSquare : public SignalStatistic |
134 | 134 | { |
135 | 135 | // Documentation inherited. |
136 | public: virtual double Value() const; | |
136 | public: virtual double Value() const override; | |
137 | 137 | |
138 | 138 | /// \brief Get a short version of the name of this statistical measure. |
139 | 139 | /// \return "rms" |
140 | public: virtual std::string ShortName() const; | |
141 | ||
142 | // Documentation inherited. | |
143 | public: virtual void InsertData(const double _data); | |
140 | public: virtual std::string ShortName() const override; | |
141 | ||
142 | // Documentation inherited. | |
143 | public: virtual void InsertData(const double _data) override; | |
144 | 144 | }; |
145 | 145 | /// \} |
146 | 146 | |
152 | 152 | class IGNITION_MATH_VISIBLE SignalMaxAbsoluteValue : public SignalStatistic |
153 | 153 | { |
154 | 154 | // Documentation inherited. |
155 | public: virtual double Value() const; | |
155 | public: virtual double Value() const override; | |
156 | 156 | |
157 | 157 | /// \brief Get a short version of the name of this statistical measure. |
158 | 158 | /// \return "maxAbs" |
159 | public: virtual std::string ShortName() const; | |
160 | ||
161 | // Documentation inherited. | |
162 | public: virtual void InsertData(const double _data); | |
159 | public: virtual std::string ShortName() const override; | |
160 | ||
161 | // Documentation inherited. | |
162 | public: virtual void InsertData(const double _data) override; | |
163 | 163 | }; |
164 | 164 | /// \} |
165 | 165 | |
169 | 169 | class IGNITION_MATH_VISIBLE SignalVariance : public SignalStatistic |
170 | 170 | { |
171 | 171 | // Documentation inherited. |
172 | public: virtual double Value() const; | |
172 | public: virtual double Value() const override; | |
173 | 173 | |
174 | 174 | /// \brief Get a short version of the name of this statistical measure. |
175 | 175 | /// \return "var" |
176 | public: virtual std::string ShortName() const; | |
177 | ||
178 | // Documentation inherited. | |
179 | public: virtual void InsertData(const double _data); | |
176 | public: virtual std::string ShortName() const override; | |
177 | ||
178 | // Documentation inherited. | |
179 | public: virtual void InsertData(const double _data) override; | |
180 | 180 | }; |
181 | 181 | /// \} |
182 | 182 | |
238 | 238 | public: void Reset(); |
239 | 239 | |
240 | 240 | /// \brief Assignment operator |
241 | /// \param[in] _v A SignalStats to copy | |
241 | /// \param[in] _s A SignalStats to copy | |
242 | 242 | /// \return this |
243 | 243 | public: SignalStats &operator=(const SignalStats &_s); |
244 | 244 |
72 | 72 | |
73 | 73 | /// \brief Get the mass matrix for this sphere. This function |
74 | 74 | /// is only meaningful if the sphere's radius and material have been set. |
75 | /// \param[out] _massMatrix The computed mass matrix will be stored | |
75 | /// \param[out] _massMat The computed mass matrix will be stored | |
76 | 76 | /// here. |
77 | 77 | /// \return False if computation of the mass matrix failed, which |
78 | 78 | /// could be due to an invalid radius (<=0) or density (<=0). |
114 | 114 | /// Example: _latA = 38.0016667 and _lonA = -123.0016667) represents |
115 | 115 | /// the point with latitude 38d 0'6.00"N and longitude 123d 0'6.00"W. |
116 | 116 | /// \param[in] _latA Latitude of point A. |
117 | /// \param[in] _longA Longitude of point A. | |
117 | /// \param[in] _lonA Longitude of point A. | |
118 | 118 | /// \param[in] _latB Latitude of point B. |
119 | /// \param[in] _longB Longitude of point B. | |
119 | /// \param[in] _lonB Longitude of point B. | |
120 | 120 | /// \return Distance in meters. |
121 | 121 | public: static double Distance(const ignition::math::Angle &_latA, |
122 | 122 | const ignition::math::Angle &_lonA, |
173 | 173 | |
174 | 174 | /// \brief Convert a Cartesian velocity vector with components East, |
175 | 175 | /// North, Up to a local cartesian frame vector XYZ. |
176 | /// \param[in] Vector with components (x,y,z): (East, North, Up). | |
176 | /// \param[in] _xyz Vector with components (x,y,z): (East, North, Up). | |
177 | 177 | /// \return Cartesian vector in the world frame. |
178 | 178 | public: ignition::math::Vector3d LocalFromGlobalVelocity( |
179 | 179 | const ignition::math::Vector3d &_xyz) const; |
197 | 197 | /// \brief Interpolates the mth derivative of the spline at |
198 | 198 | /// parameter value \p _t. |
199 | 199 | /// \param[in] _mth order of curve derivative to interpolate. |
200 | /// \param[in] _t parameter value (range 0 to 1). | |
200 | /// \param[in] _1 parameter value (range 0 to 1). | |
201 | 201 | /// \return the interpolated mth derivative, or [INF, INF, INF] |
202 | 202 | /// on error. Use Vector3d::IsFinite() to check for an error. |
203 | 203 | public: Vector3d InterpolateMthDerivative(const unsigned int _mth, |
210 | 210 | /// \param[in] _fromIndex point index to treat as t = 0, fromIndex + 1 |
211 | 211 | /// is deemed to be t = 1. |
212 | 212 | /// \param[in] _mth order of curve derivative to interpolate. |
213 | /// \param[in] _t parameter value (range 0 to 1). | |
213 | /// \param[in] _s parameter value (range 0 to 1). | |
214 | 214 | /// \return the interpolated mth derivative, or [INF, INF, INF] on |
215 | 215 | /// error. Use Vector3d::IsFinite() to check for an error. |
216 | 216 | public: Vector3d InterpolateMthDerivative(const unsigned int _fromIndex, |
16 | 16 | #ifndef IGNITION_MATH_VECTOR2_HH_ |
17 | 17 | #define IGNITION_MATH_VECTOR2_HH_ |
18 | 18 | |
19 | #include <algorithm> | |
20 | ||
19 | 21 | #include <ignition/math/Helpers.hh> |
20 | 22 | #include <ignition/math/config.hh> |
21 | 23 | |
64 | 66 | /// \brief Destructor |
65 | 67 | public: virtual ~Vector2() {} |
66 | 68 | |
69 | /// \brief Return the sum of the values | |
70 | /// \return the sum | |
71 | public: T Sum() const | |
72 | { | |
73 | return this->data[0] + this->data[1]; | |
74 | } | |
75 | ||
67 | 76 | /// \brief Calc distance to the given point |
68 | 77 | /// \param[in] _pt The point to measure to |
69 | 78 | /// \return the distance |
100 | 109 | } |
101 | 110 | } |
102 | 111 | |
112 | /// \brief Returns a normalized vector | |
113 | /// \return unit length vector | |
114 | public: Vector2 Normalized() const | |
115 | { | |
116 | Vector2<T> result = *this; | |
117 | result.Normalize(); | |
118 | return result; | |
119 | } | |
120 | ||
121 | /// \brief Round to near whole number, return the result. | |
122 | /// \return the result | |
123 | public: Vector2 Round() | |
124 | { | |
125 | this->data[0] = nearbyint(this->data[0]); | |
126 | this->data[1] = nearbyint(this->data[1]); | |
127 | return *this; | |
128 | } | |
129 | ||
130 | /// \brief Get a rounded version of this vector | |
131 | /// \return a rounded vector | |
132 | public: Vector2 Rounded() const | |
133 | { | |
134 | Vector2<T> result = *this; | |
135 | result.Round(); | |
136 | return result; | |
137 | } | |
138 | ||
103 | 139 | /// \brief Set the contents of the vector |
104 | 140 | /// \param[in] _x value along x |
105 | 141 | /// \param[in] _y value along y |
115 | 151 | public: T Dot(const Vector2<T> &_v) const |
116 | 152 | { |
117 | 153 | return (this->data[0] * _v[0]) + (this->data[1] * _v[1]); |
154 | } | |
155 | ||
156 | /// \brief Get the absolute value of the vector | |
157 | /// \return a vector with positive elements | |
158 | public: Vector2 Abs() const | |
159 | { | |
160 | return Vector2(std::abs(this->data[0]), | |
161 | std::abs(this->data[1])); | |
162 | } | |
163 | ||
164 | /// \brief Return the absolute dot product of this vector and | |
165 | /// another vector. This is similar to the Dot function, except the | |
166 | /// absolute value of each component of the vector is used. | |
167 | /// | |
168 | /// result = abs(x1 * x2) + abs(y1 * y2) | |
169 | /// | |
170 | /// \param[in] _v The vector | |
171 | /// \return The absolute dot product | |
172 | public: T AbsDot(const Vector2<T> &_v) const | |
173 | { | |
174 | return std::abs(this->data[0] * _v[0]) + | |
175 | std::abs(this->data[1] * _v[1]); | |
176 | } | |
177 | ||
178 | /// \brief Corrects any nan values | |
179 | public: inline void Correct() | |
180 | { | |
181 | // std::isfinite works with floating point values, | |
182 | // need to explicit cast to avoid ambiguity in vc++. | |
183 | if (!std::isfinite(static_cast<double>(this->data[0]))) | |
184 | this->data[0] = 0; | |
185 | if (!std::isfinite(static_cast<double>(this->data[1]))) | |
186 | this->data[1] = 0; | |
187 | } | |
188 | ||
189 | /// \brief Set this vector's components to the maximum of itself and the | |
190 | /// passed in vector | |
191 | /// \param[in] _v the maximum clamping vector | |
192 | public: void Max(const Vector2<T> &_v) | |
193 | { | |
194 | this->data[0] = std::max(_v[0], this->data[0]); | |
195 | this->data[1] = std::max(_v[1], this->data[1]); | |
196 | } | |
197 | ||
198 | /// \brief Set this vector's components to the minimum of itself and the | |
199 | /// passed in vector | |
200 | /// \param[in] _v the minimum clamping vector | |
201 | public: void Min(const Vector2<T> &_v) | |
202 | { | |
203 | this->data[0] = std::min(_v[0], this->data[0]); | |
204 | this->data[1] = std::min(_v[1], this->data[1]); | |
205 | } | |
206 | ||
207 | /// \brief Get the maximum value in the vector | |
208 | /// \return the maximum element | |
209 | public: T Max() const | |
210 | { | |
211 | return std::max(this->data[0], this->data[1]); | |
212 | } | |
213 | ||
214 | /// \brief Get the minimum value in the vector | |
215 | /// \return the minimum element | |
216 | public: T Min() const | |
217 | { | |
218 | return std::min(this->data[0], this->data[1]); | |
118 | 219 | } |
119 | 220 | |
120 | 221 | /// \brief Assignment operator |
321 | 321 | } |
322 | 322 | |
323 | 323 | /// \brief Assignment operator |
324 | /// \param[in] _value assigned to all elements | |
324 | /// \param[in] _v assigned to all elements | |
325 | 325 | /// \return this |
326 | 326 | public: Vector3 &operator=(T _v) |
327 | 327 | { |
16 | 16 | #ifndef IGNITION_MATH_VECTOR4_HH_ |
17 | 17 | #define IGNITION_MATH_VECTOR4_HH_ |
18 | 18 | |
19 | #include <algorithm> | |
20 | ||
19 | 21 | #include <ignition/math/Matrix4.hh> |
20 | 22 | #include <ignition/math/Helpers.hh> |
21 | 23 | #include <ignition/math/config.hh> |
81 | 83 | (this->data[3]-_pt[3])*(this->data[3]-_pt[3])); |
82 | 84 | } |
83 | 85 | |
86 | /// \brief Calc distance to the given point | |
87 | /// \param[in] _x value along x | |
88 | /// \param[in] _y value along y | |
89 | /// \param[in] _z value along z | |
90 | /// \param[in] _w value along w | |
91 | /// \return the distance | |
92 | public: T Distance(T _x, T _y, T _z, T _w) const | |
93 | { | |
94 | return this->Distance(Vector4(_x, _y, _z, _w)); | |
95 | } | |
96 | ||
84 | 97 | /// \brief Returns the length (magnitude) of the vector |
85 | 98 | /// \return The length |
86 | 99 | public: T Length() const |
96 | 109 | + std::pow(this->data[1], 2) |
97 | 110 | + std::pow(this->data[2], 2) |
98 | 111 | + std::pow(this->data[3], 2); |
112 | } | |
113 | ||
114 | /// \brief Round to near whole number. | |
115 | public: void Round() | |
116 | { | |
117 | this->data[0] = nearbyint(this->data[0]); | |
118 | this->data[1] = nearbyint(this->data[1]); | |
119 | this->data[2] = nearbyint(this->data[2]); | |
120 | this->data[3] = nearbyint(this->data[3]); | |
121 | } | |
122 | ||
123 | /// \brief Get a rounded version of this vector | |
124 | /// \return a rounded vector | |
125 | public: Vector4 Rounded() const | |
126 | { | |
127 | Vector4<T> result = *this; | |
128 | result.Round(); | |
129 | return result; | |
130 | } | |
131 | ||
132 | /// \brief Corrects any nan values | |
133 | public: inline void Correct() | |
134 | { | |
135 | // std::isfinite works with floating point values, | |
136 | // need to explicit cast to avoid ambiguity in vc++. | |
137 | if (!std::isfinite(static_cast<double>(this->data[0]))) | |
138 | this->data[0] = 0; | |
139 | if (!std::isfinite(static_cast<double>(this->data[1]))) | |
140 | this->data[1] = 0; | |
141 | if (!std::isfinite(static_cast<double>(this->data[2]))) | |
142 | this->data[2] = 0; | |
143 | if (!std::isfinite(static_cast<double>(this->data[3]))) | |
144 | this->data[3] = 0; | |
99 | 145 | } |
100 | 146 | |
101 | 147 | /// \brief Normalize the vector length |
112 | 158 | } |
113 | 159 | } |
114 | 160 | |
161 | /// \brief Return a normalized vector | |
162 | /// \return unit length vector | |
163 | public: Vector4 Normalized() const | |
164 | { | |
165 | Vector4<T> result = *this; | |
166 | result.Normalize(); | |
167 | return result; | |
168 | } | |
169 | ||
170 | /// \brief Return the dot product of this vector and another vector | |
171 | /// \param[in] _v the vector | |
172 | /// \return the dot product | |
173 | public: T Dot(const Vector4<T> &_v) const | |
174 | { | |
175 | return this->data[0] * _v[0] + | |
176 | this->data[1] * _v[1] + | |
177 | this->data[2] * _v[2] + | |
178 | this->data[3] * _v[3]; | |
179 | } | |
180 | ||
181 | /// \brief Return the absolute dot product of this vector and | |
182 | /// another vector. This is similar to the Dot function, except the | |
183 | /// absolute value of each component of the vector is used. | |
184 | /// | |
185 | /// result = abs(x1 * x2) + abs(y1 * y2) + abs(z1 * z2) + abs(w1 * w2) | |
186 | /// | |
187 | /// \param[in] _v the vector | |
188 | /// \return The absolute dot product | |
189 | public: T AbsDot(const Vector4<T> &_v) const | |
190 | { | |
191 | return std::abs(this->data[0] * _v[0]) + | |
192 | std::abs(this->data[1] * _v[1]) + | |
193 | std::abs(this->data[2] * _v[2]) + | |
194 | std::abs(this->data[3] * _v[3]); | |
195 | } | |
196 | ||
197 | /// \brief Get the absolute value of the vector | |
198 | /// \return a vector with positive elements | |
199 | public: Vector4 Abs() const | |
200 | { | |
201 | return Vector4(std::abs(this->data[0]), | |
202 | std::abs(this->data[1]), | |
203 | std::abs(this->data[2]), | |
204 | std::abs(this->data[3])); | |
205 | } | |
206 | ||
115 | 207 | /// \brief Set the contents of the vector |
116 | 208 | /// \param[in] _x value along x axis |
117 | 209 | /// \param[in] _y value along y axis |
125 | 217 | this->data[3] = _w; |
126 | 218 | } |
127 | 219 | |
220 | /// \brief Set this vector's components to the maximum of itself and the | |
221 | /// passed in vector | |
222 | /// \param[in] _v the maximum clamping vector | |
223 | public: void Max(const Vector4<T> &_v) | |
224 | { | |
225 | this->data[0] = std::max(_v[0], this->data[0]); | |
226 | this->data[1] = std::max(_v[1], this->data[1]); | |
227 | this->data[2] = std::max(_v[2], this->data[2]); | |
228 | this->data[3] = std::max(_v[3], this->data[3]); | |
229 | } | |
230 | ||
231 | /// \brief Set this vector's components to the minimum of itself and the | |
232 | /// passed in vector | |
233 | /// \param[in] _v the minimum clamping vector | |
234 | public: void Min(const Vector4<T> &_v) | |
235 | { | |
236 | this->data[0] = std::min(_v[0], this->data[0]); | |
237 | this->data[1] = std::min(_v[1], this->data[1]); | |
238 | this->data[2] = std::min(_v[2], this->data[2]); | |
239 | this->data[3] = std::min(_v[3], this->data[3]); | |
240 | } | |
241 | ||
242 | /// \brief Get the maximum value in the vector | |
243 | /// \return the maximum element | |
244 | public: T Max() const | |
245 | { | |
246 | return *std::max_element(this->data, this->data+4); | |
247 | } | |
248 | ||
249 | /// \brief Get the minimum value in the vector | |
250 | /// \return the minimum element | |
251 | public: T Min() const | |
252 | { | |
253 | return *std::min_element(this->data, this->data+4); | |
254 | } | |
255 | ||
256 | /// \brief Return the sum of the values | |
257 | /// \return the sum | |
258 | public: T Sum() const | |
259 | { | |
260 | return this->data[0] + this->data[1] + this->data[2] + this->data[3]; | |
261 | } | |
262 | ||
128 | 263 | /// \brief Assignment operator |
129 | 264 | /// \param[in] _v the vector |
130 | 265 | /// \return a reference to this vector |
305 | 440 | /// \brief Division assignment operator |
306 | 441 | /// \remarks Performs element wise division, |
307 | 442 | /// which has limited use. |
308 | /// \param[in] _pt another vector | |
443 | /// \param[in] _v another vector | |
309 | 444 | /// \return a result vector |
310 | 445 | public: const Vector4<T> operator/(T _v) const |
311 | 446 | { |
547 | 682 | this->data[3] = _v; |
548 | 683 | } |
549 | 684 | |
685 | /// \brief Less than operator. | |
686 | /// \param[in] _pt Vector to compare. | |
687 | /// \return True if this vector's X(), Y(), Z() or W() value is less | |
688 | /// than the given vector's corresponding values. | |
689 | public: bool operator<(const Vector4<T> &_pt) const | |
690 | { | |
691 | return this->data[0] < _pt[0] || this->data[1] < _pt[1] || | |
692 | this->data[2] < _pt[2] || this->data[3] < _pt[3]; | |
693 | } | |
694 | ||
550 | 695 | /// \brief Stream insertion operator |
551 | 696 | /// \param[in] _out output stream |
552 | 697 | /// \param[in] _pt Vector4 to output |
0 | 0 | /* Config.hh. Generated by CMake for @PROJECT_NAME_NO_VERSION@. */ |
1 | 1 | |
2 | 2 | /* Version number */ |
3 | #define IGNITION_MATH_MAJOR_VERSION ${PROJECT_MAJOR_VERSION} | |
4 | #define IGNITION_MATH_MINOR_VERSION ${PROJECT_MINOR_VERSION} | |
5 | #define IGNITION_MATH_PATCH_VERSION ${PROJECT_PATCH_VERSION} | |
3 | #define IGNITION_MATH_MAJOR_VERSION ${PROJECT_VERSION_MAJOR} | |
4 | #define IGNITION_MATH_MINOR_VERSION ${PROJECT_VERSION_MINOR} | |
5 | #define IGNITION_MATH_PATCH_VERSION ${PROJECT_VERSION_PATCH} | |
6 | 6 | |
7 | 7 | #define IGNITION_MATH_VERSION "${PROJECT_VERSION}" |
8 | 8 | #define IGNITION_MATH_VERSION_FULL "${PROJECT_VERSION_FULL}" |
9 | 9 | |
10 | 10 | #define IGNITION_MATH_VERSION_NAMESPACE v${PROJECT_VERSION_MAJOR} |
11 | 11 | |
12 | #define IGNITION_MATH_VERSION_HEADER "Ignition math, version ${PROJECT_VERSION_FULL}\nCopyright (C) 2014 Open Source Robotics Foundation.\nReleased under the Apache 2.0 License.\n\n" | |
12 | #define IGNITION_MATH_VERSION_HEADER "Ignition ${IGN_DESIGNATION}, version ${PROJECT_VERSION_FULL}\nCopyright (C) 2014 Open Source Robotics Foundation.\nReleased under the Apache 2.0 License.\n\n" | |
13 | 13 | |
14 | 14 | #cmakedefine IGNITION_MATH_BUILD_TYPE_PROFILE 1 |
15 | 15 | #cmakedefine IGNITION_MATH_BUILD_TYPE_DEBUG 1 |
0 | /* | |
1 | * Copyright (C) 2020 Open Source Robotics Foundation | |
2 | * | |
3 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
4 | * you may not use this file except in compliance with the License. | |
5 | * You may obtain a copy of the License at | |
6 | * | |
7 | * http://www.apache.org/licenses/LICENSE-2.0 | |
8 | * | |
9 | * Unless required by applicable law or agreed to in writing, software | |
10 | * distributed under the License is distributed on an "AS IS" BASIS, | |
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 | * See the License for the specific language governing permissions and | |
13 | * limitations under the License. | |
14 | * | |
15 | */ | |
16 | #ifndef IGNITION_MATH_DETAIL_CAPSULE_HH_ | |
17 | #define IGNITION_MATH_DETAIL_CAPSULE_HH_ | |
18 | ||
19 | #include <limits> | |
20 | #include <optional> | |
21 | #include <ignition/math/Helpers.hh> | |
22 | #include <ignition/math/Inertial.hh> | |
23 | ||
24 | namespace ignition | |
25 | { | |
26 | namespace math | |
27 | { | |
28 | ||
29 | ////////////////////////////////////////////////// | |
30 | template<typename T> | |
31 | Capsule<T>::Capsule(const T _length, const T _radius) | |
32 | { | |
33 | this->length = _length; | |
34 | this->radius = _radius; | |
35 | } | |
36 | ||
37 | ////////////////////////////////////////////////// | |
38 | template<typename T> | |
39 | Capsule<T>::Capsule(const T _length, const T _radius, const Material &_mat) | |
40 | { | |
41 | this->length = _length; | |
42 | this->radius = _radius; | |
43 | this->material = _mat; | |
44 | } | |
45 | ||
46 | ////////////////////////////////////////////////// | |
47 | template<typename T> | |
48 | T Capsule<T>::Radius() const | |
49 | { | |
50 | return this->radius; | |
51 | } | |
52 | ||
53 | ////////////////////////////////////////////////// | |
54 | template<typename T> | |
55 | void Capsule<T>::SetRadius(const T _radius) | |
56 | { | |
57 | this->radius = _radius; | |
58 | } | |
59 | ||
60 | ////////////////////////////////////////////////// | |
61 | template<typename T> | |
62 | T Capsule<T>::Length() const | |
63 | { | |
64 | return this->length; | |
65 | } | |
66 | ||
67 | ////////////////////////////////////////////////// | |
68 | template<typename T> | |
69 | void Capsule<T>::SetLength(const T _length) | |
70 | { | |
71 | this->length = _length; | |
72 | } | |
73 | ||
74 | ////////////////////////////////////////////////// | |
75 | template<typename T> | |
76 | const Material &Capsule<T>::Mat() const | |
77 | { | |
78 | return this->material; | |
79 | } | |
80 | ||
81 | ////////////////////////////////////////////////// | |
82 | template<typename T> | |
83 | void Capsule<T>::SetMat(const Material &_mat) | |
84 | { | |
85 | this->material = _mat; | |
86 | } | |
87 | ||
88 | ////////////////////////////////////////////////// | |
89 | template<typename T> | |
90 | bool Capsule<T>::operator==(const Capsule &_capsule) const | |
91 | { | |
92 | return equal(this->radius, _capsule.Radius()) && | |
93 | equal(this->length, _capsule.Length()) && | |
94 | this->material == _capsule.Mat(); | |
95 | } | |
96 | ||
97 | ////////////////////////////////////////////////// | |
98 | template<typename T> | |
99 | std::optional< MassMatrix3<T> > Capsule<T>::MassMatrix() const | |
100 | { | |
101 | // mass and moment of inertia of cylinder about centroid | |
102 | MassMatrix3<T> cylinder; | |
103 | cylinder.SetFromCylinderZ(this->material, this->length, this->radius); | |
104 | ||
105 | // mass and moment of inertia of hemisphere about centroid | |
106 | const T r2 = this->radius * this->radius; | |
107 | const T hemisphereMass = this->material.Density() * | |
108 | 2. / 3. * IGN_PI * r2 * this->radius; | |
109 | // efunda.com/math/solids/solids_display.cfm?SolidName=Hemisphere | |
110 | const T ixx = 83. / 320. * hemisphereMass * r2; | |
111 | const T izz = 2. / 5. * hemisphereMass * r2; | |
112 | MassMatrix3<T> hemisphere(hemisphereMass, Vector3<T>(ixx, ixx, izz), | |
113 | Vector3<T>::Zero);; | |
114 | ||
115 | // Distance from centroid of cylinder to centroid of hemisphere, | |
116 | // since centroid of hemisphere is 3/8 radius from its flat base | |
117 | const T dz = this->length / 2. + this->radius * 3. / 8.; | |
118 | Inertial<T> upperCap(hemisphere, Pose3<T>(0, 0, dz, 0, 0, 0)); | |
119 | Inertial<T> lowerCap(hemisphere, Pose3<T>(0, 0, -dz, 0, 0, 0)); | |
120 | ||
121 | // Use Inertial class to add MassMatrix3 objects at different poses | |
122 | Inertial<T> capsule = | |
123 | Inertial<T>(cylinder, Pose3<T>::Zero) + upperCap + lowerCap; | |
124 | ||
125 | if (!capsule.MassMatrix().IsValid()) | |
126 | { | |
127 | return std::nullopt; | |
128 | } | |
129 | ||
130 | return std::make_optional(capsule.MassMatrix()); | |
131 | } | |
132 | ||
133 | ////////////////////////////////////////////////// | |
134 | template<typename T> | |
135 | T Capsule<T>::Volume() const | |
136 | { | |
137 | return IGN_PI * std::pow(this->radius, 2) * | |
138 | (this->length + 4. / 3. * this->radius); | |
139 | } | |
140 | ||
141 | ////////////////////////////////////////////////// | |
142 | template<typename T> | |
143 | bool Capsule<T>::SetDensityFromMass(const T _mass) | |
144 | { | |
145 | T newDensity = this->DensityFromMass(_mass); | |
146 | if (isnan(newDensity)) | |
147 | return false; | |
148 | ||
149 | this->material.SetDensity(newDensity); | |
150 | return true; | |
151 | } | |
152 | ||
153 | ////////////////////////////////////////////////// | |
154 | template<typename T> | |
155 | T Capsule<T>::DensityFromMass(const T _mass) const | |
156 | { | |
157 | if (this->radius <= 0 || this->length <=0 || _mass <= 0) | |
158 | return std::numeric_limits<T>::quiet_NaN(); | |
159 | ||
160 | return _mass / this->Volume(); | |
161 | } | |
162 | ||
163 | } | |
164 | } | |
165 | #endif |
34 | 34 | inline namespace IGNITION_MATH_VERSION_NAMESPACE { |
35 | 35 | namespace graph |
36 | 36 | { |
37 | /// \def EdgeId. | |
37 | /// \typedef EdgeId. | |
38 | 38 | /// \brief The unique Id for an edge. |
39 | 39 | using EdgeId = uint64_t; |
40 | 40 | |
160 | 160 | /// (v1) and the head end (v2): (v1)->(v2). The operation e2.To(v1) |
161 | 161 | /// returns kNullId. The operation e2.To(v2) returns v1. |
162 | 162 | /// |
163 | /// \param[in] _from Destination vertex. | |
163 | /// \param[in] _to Destination vertex. | |
164 | 164 | /// \return The other vertex of the edge that can reach "_to" |
165 | 165 | /// vertex or kNullId otherwise. |
166 | 166 | public: virtual VertexId To(const VertexId &_to) const = 0; |
243 | 243 | /// description language. |
244 | 244 | /// \param[out] _out The output stream. |
245 | 245 | /// \param[in] _e Edge to write to the stream. |
246 | /// \ref https://en.wikipedia.org/wiki/DOT_(graph_description_language). | |
246 | /// \sa https://en.wikipedia.org/wiki/DOT_(graph_description_language). | |
247 | 247 | public: friend std::ostream &operator<<(std::ostream &_out, |
248 | 248 | const UndirectedEdge<E> &_e) |
249 | 249 | { |
319 | 319 | /// description language. |
320 | 320 | /// \param[out] _out The output stream. |
321 | 321 | /// \param[in] _e Edge to write to the stream. |
322 | /// \ref https://en.wikipedia.org/wiki/DOT_(graph_description_language). | |
322 | /// \sa https://en.wikipedia.org/wiki/DOT_(graph_description_language). | |
323 | 323 | public: friend std::ostream &operator<<(std::ostream &_out, |
324 | 324 | const DirectedEdge<E> &_e) |
325 | 325 | { |
204 | 204 | /// \brief Add a new edge to the graph. |
205 | 205 | /// \param[in] _vertices The set of Ids of the two vertices. |
206 | 206 | /// \param[in] _data User data. |
207 | /// \param[in] _weight Edge weight. | |
207 | 208 | /// \return Reference to the new edge created or NullEdge if the |
208 | 209 | /// edge was not created (e.g. incorrect vertices). |
209 | 210 | public: EdgeType &AddEdge(const VertexId_P &_vertices, |
683 | 684 | /// description language. |
684 | 685 | /// \param[out] _out The output stream. |
685 | 686 | /// \param[in] _g Graph to write to the stream. |
686 | /// \ref https://en.wikipedia.org/wiki/DOT_(graph_description_language). | |
687 | /// \sa https://en.wikipedia.org/wiki/DOT_(graph_description_language). | |
687 | 688 | public: template<typename VV, typename EE, typename EEdgeType> |
688 | 689 | friend std::ostream &operator<<(std::ostream &_out, |
689 | 690 | const Graph<VV, EE, EEdgeType> &_g); |
36 | 36 | inline namespace IGNITION_MATH_VERSION_NAMESPACE { |
37 | 37 | namespace graph |
38 | 38 | { |
39 | /// \def CostInfo. | |
39 | /// \typedef CostInfo. | |
40 | 40 | /// \brief Used in Dijkstra. For a given source vertex, this pair represents |
41 | 41 | /// the cost (first element) to reach a destination vertex (second element). |
42 | 42 | using CostInfo = std::pair<double, VertexId>; |
281 | 281 | /// A connected component of an undirected graph is a subgraph in which any |
282 | 282 | /// two vertices are connected to each other by paths, and which is connected |
283 | 283 | /// to no additional vertices in the supergraph. |
284 | /// \ref https://en.wikipedia.org/wiki/Connected_component_(graph_theory) | |
284 | /// \sa https://en.wikipedia.org/wiki/Connected_component_(graph_theory) | |
285 | 285 | /// \param[in] _graph A graph. |
286 | 286 | /// \return A vector of graphs. Each element of the graph is a component |
287 | 287 | /// (subgraph) of the original graph. |
324 | 324 | |
325 | 325 | return res; |
326 | 326 | } |
327 | ||
328 | /// \brief Copy a DirectedGraph to an UndirectedGraph with the same vertices | |
329 | /// and edges. | |
330 | /// \param[in] _graph A directed graph. | |
331 | /// \return An undirected graph with the same vertices and edges as the | |
332 | /// original graph. | |
333 | template<typename V, typename E> | |
334 | UndirectedGraph<V, E> ToUndirectedGraph(const DirectedGraph<V, E> &_graph) | |
335 | { | |
336 | std::vector<Vertex<V>> vertices; | |
337 | std::vector<EdgeInitializer<E>> edges; | |
338 | ||
339 | // Add all vertices. | |
340 | for (auto const &vPair : _graph.Vertices()) | |
341 | { | |
342 | vertices.push_back(vPair.second.get()); | |
343 | } | |
344 | ||
345 | // Add all edges. | |
346 | for (auto const &ePair : _graph.Edges()) | |
347 | { | |
348 | auto const &e = ePair.second.get(); | |
349 | edges.push_back({e.Vertices(), e.Data(), e.Weight()}); | |
350 | } | |
351 | ||
352 | return UndirectedGraph<V, E>(vertices, edges); | |
353 | } | |
327 | 354 | } |
328 | 355 | } |
329 | 356 | } |
35 | 35 | inline namespace IGNITION_MATH_VERSION_NAMESPACE { |
36 | 36 | namespace graph |
37 | 37 | { |
38 | /// \def VertexId. | |
38 | /// \typedef VertexId. | |
39 | 39 | /// \brief The unique Id of each vertex. |
40 | 40 | using VertexId = uint64_t; |
41 | 41 | |
114 | 114 | /// description language. |
115 | 115 | /// \param[out] _out The output stream. |
116 | 116 | /// \param[in] _v Vertex to write to the stream. |
117 | /// \ref https://en.wikipedia.org/wiki/DOT_(graph_description_language). | |
117 | /// \sa https://en.wikipedia.org/wiki/DOT_(graph_description_language). | |
118 | 118 | public: friend std::ostream &operator<<(std::ostream &_out, |
119 | 119 | const Vertex<V> &_v) |
120 | 120 | { |
53 | 53 | } |
54 | 54 | |
55 | 55 | ////////////////////////////////////////////////// |
56 | void Angle::SetRadian(double _radian) | |
57 | { | |
58 | this->value = _radian; | |
59 | } | |
60 | ||
61 | ////////////////////////////////////////////////// | |
56 | 62 | void Angle::Degree(double _degree) |
63 | { | |
64 | this->value = _degree * IGN_PI / 180.0; | |
65 | } | |
66 | ||
67 | ////////////////////////////////////////////////// | |
68 | void Angle::SetDegree(double _degree) | |
57 | 69 | { |
58 | 70 | this->value = _degree * IGN_PI / 180.0; |
59 | 71 | } |
74 | 86 | void Angle::Normalize() |
75 | 87 | { |
76 | 88 | this->value = atan2(sin(this->value), cos(this->value)); |
89 | } | |
90 | ||
91 | ////////////////////////////////////////////////// | |
92 | Angle Angle::Normalized() const | |
93 | { | |
94 | return atan2(sin(this->value), cos(this->value)); | |
77 | 95 | } |
78 | 96 | |
79 | 97 | ////////////////////////////////////////////////// |
33 | 33 | public: Angle(double _radian); |
34 | 34 | public: Angle(const Angle &_angle); |
35 | 35 | public: virtual ~Angle(); |
36 | public: void Radian(double _radian); | |
37 | public: void Degree(double _degree); | |
36 | public: void SetRadian(double _radian); | |
37 | public: void SetDegree(double _degree); | |
38 | 38 | public: double Radian() const; |
39 | 39 | public: double Degree() const; |
40 | 40 | public: void Normalize(); |
41 | public: Angle Normalized() const; | |
41 | 42 | public: inline double operator*() const; |
42 | 43 | public: Angle operator-(const Angle &_angle) const; |
43 | 44 | public: Angle operator+(const Angle &_angle) const; |
29 | 29 | math::Angle angle1; |
30 | 30 | EXPECT_TRUE(math::equal(0.0, angle1.Radian())); |
31 | 31 | |
32 | angle1.SetDegree(90.0); | |
33 | EXPECT_TRUE(angle1 == IGN_PI_2); | |
32 | 34 | angle1.Degree(180.0); |
33 | 35 | EXPECT_TRUE(angle1 == IGN_PI); |
34 | 36 | |
44 | 46 | math::Angle angle(0.5); |
45 | 47 | EXPECT_TRUE(math::equal(0.5, angle.Radian())); |
46 | 48 | |
49 | angle.SetRadian(IGN_PI_2); | |
50 | EXPECT_TRUE(math::equal(IGN_RTOD(IGN_PI_2), angle.Degree())); | |
51 | ||
47 | 52 | angle.Radian(IGN_PI); |
48 | 53 | EXPECT_TRUE(math::equal(IGN_RTOD(IGN_PI), angle.Degree())); |
49 | 54 | |
55 | math::Angle normalized = angle.Normalized(); | |
50 | 56 | angle.Normalize(); |
51 | 57 | EXPECT_TRUE(math::equal(IGN_RTOD(IGN_PI), angle.Degree())); |
58 | EXPECT_EQ(normalized, angle); | |
52 | 59 | |
53 | 60 | angle = math::Angle(0.1) + math::Angle(0.2); |
54 | 61 | EXPECT_TRUE(math::equal(0.3, angle.Radian())); |
24 | 24 | assert(angle1.Radian() == 0.0, |
25 | 25 | "Angle::Radian() should equal zero") |
26 | 26 | |
27 | angle1.Degree(180.0) | |
27 | angle1.SetDegree(180.0) | |
28 | 28 | assert(angle1 == Ignition::Math::Angle.Pi, |
29 | 29 | "180.0 degrees should equal PI") |
30 | 30 | |
52 | 52 | angle = Ignition::Math::Angle.new(0.5) |
53 | 53 | assert(0.5 == angle.Radian, "Angle should equal 0.5") |
54 | 54 | |
55 | angle.Radian(Math::PI) | |
55 | angle.SetRadian(Math::PI) | |
56 | 56 | assert(Ignition::Math::Angle.Pi.Degree == angle.Degree, |
57 | "Pi in degrees should equal Angle.Radian(Pi).Degree") | |
57 | "Pi in degrees should equal Angle.SetRadian(Pi).Degree") | |
58 | ||
59 | angleNorm = angle.Normalized() | |
58 | 60 | |
59 | 61 | angle.Normalize() |
60 | 62 | assert(Ignition::Math::Angle.new(Math::PI).Degree == angle.Degree, |
61 | 63 | "Normalized angle should equal PI") |
64 | assert(angleNorm == angle, "Normalized angles should be equal") | |
62 | 65 | |
63 | 66 | angle = Ignition::Math::Angle.new(0.1) + Ignition::Math::Angle.new(0.2) |
64 | 67 | assert((angle.Radian - 0.3).abs < 1e-6, "Angle should equal 0.3") |
158 | 158 | } |
159 | 159 | |
160 | 160 | ////////////////////////////////////////////////// |
161 | AxisAlignedBox AxisAlignedBox::operator+(const Vector3d &_v) | |
162 | { | |
163 | return AxisAlignedBox(this->dataPtr->min + _v, this->dataPtr->max + _v); | |
164 | } | |
165 | ||
166 | ////////////////////////////////////////////////// | |
161 | 167 | bool AxisAlignedBox::Intersects(const AxisAlignedBox &_box) const |
162 | 168 | { |
163 | 169 | // Check the six separating planes. |
277 | 283 | dir.Normalize(); |
278 | 284 | return this->Intersect(Line3d(_origin + dir * _min, _origin + dir * _max)); |
279 | 285 | } |
286 | ///////////////////////////////////////////////// | |
287 | double AxisAlignedBox::Volume() const | |
288 | { | |
289 | return this->XLength() * this->YLength() * this->ZLength(); | |
290 | } | |
280 | 291 | |
281 | 292 | ///////////////////////////////////////////////// |
282 | 293 | // Find the intersection of a line from v0 to v1 and an |
208 | 208 | } |
209 | 209 | |
210 | 210 | ///////////////////////////////////////////////// |
211 | TEST(AxisAlignedBoxTest, Plus) | |
212 | { | |
213 | AxisAlignedBox box1(1, 2, 3, 4, 5, 6); | |
214 | Vector3d add(1, 1, 1); | |
215 | ||
216 | AxisAlignedBox box2 = box1 + add; | |
217 | EXPECT_EQ(box2.Min(), box1.Min() + add); | |
218 | EXPECT_EQ(box2.Max(), box1.Max() + add); | |
219 | } | |
220 | ||
221 | ///////////////////////////////////////////////// | |
211 | 222 | TEST(AxisAlignedBoxTest, PlusEmpty) |
212 | 223 | { |
213 | 224 | AxisAlignedBox box1; |
238 | 249 | box.Merge(AxisAlignedBox(Vector3d(-1, -1, -1), Vector3d(2, 2, 2))); |
239 | 250 | EXPECT_TRUE(box == AxisAlignedBox(Vector3d(-1, -2, -1), |
240 | 251 | Vector3d(2, 2, 3))); |
252 | } | |
253 | ||
254 | ///////////////////////////////////////////////// | |
255 | TEST_F(ExampleAxisAlignedBox, Volume) | |
256 | { | |
257 | EXPECT_DOUBLE_EQ(1.0, box.Volume()); | |
241 | 258 | } |
242 | 259 | |
243 | 260 | ///////////////////////////////////////////////// |
565 | 582 | Vector3d(-0.707107, 0, -0.707107), 0, 1000)), dist, 1e-5); |
566 | 583 | EXPECT_EQ(pt, Vector3d(1, 0, 0.3)); |
567 | 584 | } |
585 | ||
586 | ///////////////////////////////////////////////// | |
587 | TEST(AxisAlignedBoxTest, Volume) | |
588 | { | |
589 | AxisAlignedBox box; | |
590 | EXPECT_DOUBLE_EQ(0.0, box.Volume()); | |
591 | ||
592 | AxisAlignedBox box2(math::Vector3d(-1, -2, -3), math::Vector3d(1, 2, 3)); | |
593 | EXPECT_DOUBLE_EQ(48.0, box2.Volume()); | |
594 | } |
22 | 22 | set(swig_files |
23 | 23 | ruby |
24 | 24 | Angle |
25 | GaussMarkovProcess | |
26 | Rand | |
25 | 27 | Vector2 |
26 | Vector3) | |
28 | Vector3 | |
29 | Vector4) | |
27 | 30 | endif() |
28 | 31 | |
29 | 32 | ################################################# |
0 | /* | |
1 | * Copyright (C) 2020 Open Source Robotics Foundation | |
2 | * | |
3 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
4 | * you may not use this file except in compliance with the License. | |
5 | * You may obtain a copy of the License at | |
6 | * | |
7 | * http://www.apache.org/licenses/LICENSE-2.0 | |
8 | * | |
9 | * Unless required by applicable law or agreed to in writing, software | |
10 | * distributed under the License is distributed on an "AS IS" BASIS, | |
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 | * See the License for the specific language governing permissions and | |
13 | * limitations under the License. | |
14 | * | |
15 | */ | |
16 | #include <gtest/gtest.h> | |
17 | #include <cmath> | |
18 | #include <iostream> | |
19 | ||
20 | #include "ignition/math/Capsule.hh" | |
21 | #include "ignition/math/Helpers.hh" | |
22 | ||
23 | using namespace ignition; | |
24 | ||
25 | ///////////////////////////////////////////////// | |
26 | TEST(CapsuleTest, Constructor) | |
27 | { | |
28 | // Default constructor | |
29 | { | |
30 | math::Capsuled capsule; | |
31 | EXPECT_DOUBLE_EQ(0.0, capsule.Length()); | |
32 | EXPECT_DOUBLE_EQ(0.0, capsule.Radius()); | |
33 | EXPECT_EQ(math::Material(), capsule.Mat()); | |
34 | ||
35 | math::Capsuled capsule2; | |
36 | EXPECT_EQ(capsule, capsule2); | |
37 | } | |
38 | ||
39 | // Length and radius constructor | |
40 | { | |
41 | math::Capsuled capsule(1.0, 2.0); | |
42 | EXPECT_DOUBLE_EQ(1.0, capsule.Length()); | |
43 | EXPECT_DOUBLE_EQ(2.0, capsule.Radius()); | |
44 | EXPECT_EQ(math::Material(), capsule.Mat()); | |
45 | ||
46 | math::Capsuled capsule2(1.0, 2.0); | |
47 | EXPECT_EQ(capsule, capsule2); | |
48 | } | |
49 | ||
50 | // Length, radius, mat | |
51 | { | |
52 | math::Capsuled capsule(1.0, 2.0, | |
53 | math::Material(math::MaterialType::WOOD)); | |
54 | EXPECT_DOUBLE_EQ(1.0, capsule.Length()); | |
55 | EXPECT_DOUBLE_EQ(2.0, capsule.Radius()); | |
56 | EXPECT_EQ(math::Material(math::MaterialType::WOOD), capsule.Mat()); | |
57 | ||
58 | math::Capsuled capsule2(1.0, 2.0, | |
59 | math::Material(math::MaterialType::WOOD)); | |
60 | EXPECT_EQ(capsule, capsule2); | |
61 | } | |
62 | } | |
63 | ||
64 | ////////////////////////////////////////////////// | |
65 | TEST(CapsuleTest, Mutators) | |
66 | { | |
67 | math::Capsuled capsule; | |
68 | EXPECT_DOUBLE_EQ(0.0, capsule.Length()); | |
69 | EXPECT_DOUBLE_EQ(0.0, capsule.Radius()); | |
70 | EXPECT_EQ(math::Material(), capsule.Mat()); | |
71 | ||
72 | capsule.SetLength(100.1); | |
73 | capsule.SetRadius(.123); | |
74 | capsule.SetMat(math::Material(math::MaterialType::PINE)); | |
75 | ||
76 | EXPECT_DOUBLE_EQ(100.1, capsule.Length()); | |
77 | EXPECT_DOUBLE_EQ(.123, capsule.Radius()); | |
78 | EXPECT_EQ(math::Material(math::MaterialType::PINE), capsule.Mat()); | |
79 | } | |
80 | ||
81 | ////////////////////////////////////////////////// | |
82 | TEST(CapsuleTest, VolumeAndDensity) | |
83 | { | |
84 | double mass = 1.0; | |
85 | math::Capsuled capsule(1.0, 0.001); | |
86 | double expectedVolume = (IGN_PI * std::pow(0.001, 2) * (1.0 + 4./3. * 0.001)); | |
87 | EXPECT_DOUBLE_EQ(expectedVolume, capsule.Volume()); | |
88 | ||
89 | double expectedDensity = mass / expectedVolume; | |
90 | EXPECT_DOUBLE_EQ(expectedDensity, capsule.DensityFromMass(mass)); | |
91 | ||
92 | // Bad density | |
93 | math::Capsuled capsule2; | |
94 | EXPECT_TRUE(math::isnan(capsule2.DensityFromMass(mass))); | |
95 | } | |
96 | ||
97 | ////////////////////////////////////////////////// | |
98 | TEST(CapsuleTest, Mass) | |
99 | { | |
100 | double mass = 2.0; | |
101 | double l = 2.0; | |
102 | double r = 0.1; | |
103 | math::Capsuled capsule(l, r); | |
104 | capsule.SetDensityFromMass(mass); | |
105 | ||
106 | const double cylinderVolume = IGN_PI * r*r * l; | |
107 | const double sphereVolume = IGN_PI * 4. / 3. * r*r*r; | |
108 | const double volume = cylinderVolume + sphereVolume; | |
109 | const double cylinderMass = mass * cylinderVolume / volume; | |
110 | const double sphereMass = mass * sphereVolume / volume; | |
111 | ||
112 | // expected values based on formula used in Open Dynamics Engine | |
113 | // https://bitbucket.org/odedevs/ode/src/0.16.2/ode/src/mass.cpp#lines-148:153 | |
114 | // and the following article: | |
115 | // https://www.gamedev.net/tutorials/_/technical/math-and-physics/capsule-inertia-tensor-r3856/ | |
116 | double ixxIyy = (1/12.0) * cylinderMass * (3*r*r + l*l) | |
117 | + sphereMass * (0.4*r*r + 0.375*r*l + 0.25*l*l); | |
118 | double izz = r*r * (0.5 * cylinderMass + 0.4 * sphereMass); | |
119 | ||
120 | math::MassMatrix3d expectedMassMat; | |
121 | expectedMassMat.SetInertiaMatrix(ixxIyy, ixxIyy, izz, 0.0, 0.0, 0.0); | |
122 | expectedMassMat.SetMass(mass); | |
123 | ||
124 | auto massMat = capsule.MassMatrix(); | |
125 | ASSERT_NE(std::nullopt, massMat); | |
126 | EXPECT_EQ(expectedMassMat, *massMat); | |
127 | EXPECT_EQ(expectedMassMat.DiagonalMoments(), massMat->DiagonalMoments()); | |
128 | EXPECT_DOUBLE_EQ(expectedMassMat.Mass(), massMat->Mass()); | |
129 | } |
336 | 336 | } |
337 | 337 | |
338 | 338 | ///////////////////////////////////////////////// |
339 | TEST(Color, OperatorStreamIn) | |
340 | { | |
341 | math::Color c(0.1f, 0.2f, 0.3f, 0.5f); | |
342 | math::Color test; | |
343 | std::stringstream ss("0.1 0.2 0.3 0.5"); | |
344 | ss >> test; | |
345 | EXPECT_EQ(c, test); | |
346 | } | |
347 | ||
348 | ///////////////////////////////////////////////// | |
349 | TEST(Color, OperatorStreamInWithoutAlpha) | |
350 | { | |
351 | math::Color c(0.1f, 0.2f, 0.3f, 1.0f); | |
352 | { | |
353 | math::Color test; | |
354 | std::stringstream ss("0.1 0.2 0.3"); | |
355 | ss.exceptions(std::stringstream::failbit); | |
356 | EXPECT_NO_THROW(ss >> test); | |
357 | EXPECT_EQ(c, test); | |
358 | } | |
359 | { | |
360 | math::Color test; | |
361 | std::stringstream ss("0.1 0.2 \t0.3 \t"); | |
362 | ss.exceptions(std::stringstream::failbit); | |
363 | EXPECT_NO_THROW(ss >> test); | |
364 | EXPECT_EQ(c, test); | |
365 | } | |
366 | ||
367 | { | |
368 | math::Color test(0.5f, 0.6f, 0.7f, 0.8f); | |
369 | std::stringstream ss("0.1 0.2 \t0.3 \t"); | |
370 | ss.exceptions(std::stringstream::failbit); | |
371 | EXPECT_NO_THROW(ss >> test); | |
372 | EXPECT_EQ(c, test); | |
373 | } | |
374 | } | |
375 | ||
376 | ///////////////////////////////////////////////// | |
339 | 377 | TEST(Color, HSV) |
340 | 378 | { |
341 | 379 | math::Color clr; |
192 | 192 | // Field of view |
193 | 193 | Angle(IGN_DTOR(45)), |
194 | 194 | // Aspect ratio |
195 | 320.0/320.0, | |
195 | 1.0, | |
196 | 196 | // Pose |
197 | 197 | Pose3d(0, 0, 0, 0, 0, IGN_PI*0.5)); |
198 | 198 | |
222 | 222 | // Field of view |
223 | 223 | Angle(IGN_DTOR(45)), |
224 | 224 | // Aspect ratio |
225 | 320.0/320.0, | |
225 | 1.0, | |
226 | 226 | // Pose |
227 | 227 | Pose3d(0, 0, 0, 0, IGN_PI*0.5, 0)); |
228 | 228 | |
253 | 253 | // Field of view |
254 | 254 | Angle(IGN_DTOR(45)), |
255 | 255 | // Aspect ratio |
256 | 320.0/320.0, | |
256 | 1.0, | |
257 | 257 | // Pose |
258 | 258 | Pose3d(0, 0, 0, 0, IGN_PI*0.5, 0)); |
259 | 259 | |
278 | 278 | // Field of view |
279 | 279 | Angle(IGN_DTOR(45)), |
280 | 280 | // Aspect ratio |
281 | 320.0/320.0, | |
281 | 1.0, | |
282 | 282 | // Pose |
283 | 283 | Pose3d(0, 0, 0, 0, IGN_PI*0.5, 0)); |
284 | 284 | |
300 | 300 | // Field of view |
301 | 301 | Angle(IGN_DTOR(45)), |
302 | 302 | // Aspect ratio |
303 | 320.0/320.0, | |
303 | 1.0, | |
304 | 304 | // Pose |
305 | 305 | Pose3d(0, 0, 0, 0, IGN_PI*0.5, 0)); |
306 | 306 | |
307 | EXPECT_DOUBLE_EQ(frustum.AspectRatio(), 320.0/320.0); | |
307 | EXPECT_DOUBLE_EQ(frustum.AspectRatio(), 1); | |
308 | 308 | |
309 | 309 | frustum.SetAspectRatio(1.3434); |
310 | 310 | |
322 | 322 | // Field of view |
323 | 323 | Angle(IGN_DTOR(45)), |
324 | 324 | // Aspect ratio |
325 | 320.0/320.0, | |
325 | 1.0, | |
326 | 326 | // Pose |
327 | 327 | Pose3d(0, 0, 0, 0, IGN_PI*0.5, 0)); |
328 | 328 |
0 | /* | |
1 | * Copyright (C) 2020 Open Source Robotics Foundation | |
2 | * | |
3 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
4 | * you may not use this file except in compliance with the License. | |
5 | * You may obtain a copy of the License at | |
6 | * | |
7 | * http://www.apache.org/licenses/LICENSE-2.0 | |
8 | * | |
9 | * Unless required by applicable law or agreed to in writing, software | |
10 | * distributed under the License is distributed on an "AS IS" BASIS, | |
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 | * See the License for the specific language governing permissions and | |
13 | * limitations under the License. | |
14 | * | |
15 | */ | |
16 | ||
17 | #include <ignition/math/GaussMarkovProcess.hh> | |
18 | #include <ignition/math/Rand.hh> | |
19 | ||
20 | using namespace ignition::math; | |
21 | ||
22 | ////////////////////////////////////////////////// | |
23 | class ignition::math::GaussMarkovProcessPrivate | |
24 | { | |
25 | /// \brief Current process value. | |
26 | public: double value{0}; | |
27 | ||
28 | /// \brief Process start value. | |
29 | public: double start{0}; | |
30 | ||
31 | /// \brief Process theta value. | |
32 | public: double theta{0}; | |
33 | ||
34 | /// \brief Process mu value. | |
35 | public: double mu{0}; | |
36 | ||
37 | /// \brief Process sigma value. | |
38 | public: double sigma{0}; | |
39 | }; | |
40 | ||
41 | ////////////////////////////////////////////////// | |
42 | GaussMarkovProcess::GaussMarkovProcess() | |
43 | : dataPtr(new GaussMarkovProcessPrivate) | |
44 | { | |
45 | } | |
46 | ||
47 | ////////////////////////////////////////////////// | |
48 | GaussMarkovProcess::GaussMarkovProcess(double _start, double _theta, double _mu, | |
49 | double _sigma) | |
50 | : dataPtr(new GaussMarkovProcessPrivate) | |
51 | { | |
52 | this->Set(_start, _theta, _mu, _sigma); | |
53 | } | |
54 | ||
55 | ////////////////////////////////////////////////// | |
56 | GaussMarkovProcess::~GaussMarkovProcess() | |
57 | { | |
58 | } | |
59 | ||
60 | ////////////////////////////////////////////////// | |
61 | void GaussMarkovProcess::Set(double _start, double _theta, double _mu, | |
62 | double _sigma) | |
63 | { | |
64 | this->dataPtr->start = _start; | |
65 | this->dataPtr->theta = std::max(0.0, _theta); | |
66 | this->dataPtr->mu = _mu; | |
67 | this->dataPtr->sigma = std::max(0.0, _sigma); | |
68 | this->Reset(); | |
69 | } | |
70 | ||
71 | ////////////////////////////////////////////////// | |
72 | void GaussMarkovProcess::Reset() | |
73 | { | |
74 | this->dataPtr->value = this->dataPtr->start; | |
75 | } | |
76 | ||
77 | ////////////////////////////////////////////////// | |
78 | double GaussMarkovProcess::Start() const | |
79 | { | |
80 | return this->dataPtr->start; | |
81 | } | |
82 | ||
83 | ////////////////////////////////////////////////// | |
84 | double GaussMarkovProcess::Value() const | |
85 | { | |
86 | return this->dataPtr->value; | |
87 | } | |
88 | ||
89 | ////////////////////////////////////////////////// | |
90 | double GaussMarkovProcess::Theta() const | |
91 | { | |
92 | return this->dataPtr->theta; | |
93 | } | |
94 | ||
95 | ////////////////////////////////////////////////// | |
96 | double GaussMarkovProcess::Mu() const | |
97 | { | |
98 | return this->dataPtr->mu; | |
99 | } | |
100 | ||
101 | ////////////////////////////////////////////////// | |
102 | double GaussMarkovProcess::Sigma() const | |
103 | { | |
104 | return this->dataPtr->sigma; | |
105 | } | |
106 | ||
107 | ////////////////////////////////////////////////// | |
108 | double GaussMarkovProcess::Update(const clock::duration &_dt) | |
109 | { | |
110 | // Time difference in seconds | |
111 | return this->Update(std::chrono::duration<double>(_dt).count()); | |
112 | } | |
113 | ||
114 | ////////////////////////////////////////////////// | |
115 | double GaussMarkovProcess::Update(double _dt) | |
116 | { | |
117 | this->dataPtr->value += this->dataPtr->theta * | |
118 | (this->dataPtr->mu - this->dataPtr->value) * _dt + | |
119 | this->dataPtr->sigma * Rand::DblNormal(0, 1); | |
120 | ||
121 | // Output the new value. | |
122 | return this->dataPtr->value; | |
123 | } |
0 | /* | |
1 | * Copyright (C) 2020 Open Source Robotics Foundation | |
2 | * | |
3 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
4 | * you may not use this file except in compliance with the License. | |
5 | * You may obtain a copy of the License at | |
6 | * | |
7 | * http://www.apache.org/licenses/LICENSE-2.0 | |
8 | * | |
9 | * Unless required by applicable law or agreed to in writing, software | |
10 | * distributed under the License is distributed on an "AS IS" BASIS, | |
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 | * See the License for the specific language governing permissions and | |
13 | * limitations under the License. | |
14 | * | |
15 | */ | |
16 | ||
17 | %module gaussMarkovProcess | |
18 | %{ | |
19 | #include <ignition/math/GaussMarkovProcess.hh> | |
20 | %} | |
21 | ||
22 | namespace ignition | |
23 | { | |
24 | namespace math | |
25 | { | |
26 | class GaussMarkovProcess | |
27 | { | |
28 | public: GaussMarkovProcess(); | |
29 | public: GaussMarkovProcess(double _start, double _theta, double _mu, | |
30 | double _sigma); | |
31 | public: ~GaussMarkovProcess(); | |
32 | public: void Set(double _start, double _theta, double _mu, double _sigma); | |
33 | public: double Start() const; | |
34 | public: double Value() const; | |
35 | public: double Theta() const; | |
36 | public: double Mu() const; | |
37 | public: double Sigma() const; | |
38 | public: void Reset(); | |
39 | public: double Update(double _dt); | |
40 | }; | |
41 | } | |
42 | } |
0 | /* | |
1 | * Copyright (C) 2020 Open Source Robotics Foundation | |
2 | * | |
3 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
4 | * you may not use this file except in compliance with the License. | |
5 | * You may obtain a copy of the License at | |
6 | * | |
7 | * http://www.apache.org/licenses/LICENSE-2.0 | |
8 | * | |
9 | * Unless required by applicable law or agreed to in writing, software | |
10 | * distributed under the License is distributed on an "AS IS" BASIS, | |
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 | * See the License for the specific language governing permissions and | |
13 | * limitations under the License. | |
14 | * | |
15 | */ | |
16 | ||
17 | #include <gtest/gtest.h> | |
18 | ||
19 | #include "ignition/math/GaussMarkovProcess.hh" | |
20 | #include "ignition/math/Helpers.hh" | |
21 | #include "ignition/math/Rand.hh" | |
22 | ||
23 | using namespace ignition; | |
24 | using namespace math; | |
25 | ||
26 | ///////////////////////////////////////////////// | |
27 | TEST(GaussMarkovProcessTest, DefaultConstructor) | |
28 | { | |
29 | GaussMarkovProcess gmp; | |
30 | EXPECT_DOUBLE_EQ(0.0, gmp.Start()); | |
31 | EXPECT_DOUBLE_EQ(0.0, gmp.Value()); | |
32 | EXPECT_DOUBLE_EQ(0.0, gmp.Theta()); | |
33 | EXPECT_DOUBLE_EQ(0.0, gmp.Mu()); | |
34 | EXPECT_DOUBLE_EQ(0.0, gmp.Sigma()); | |
35 | // EXPECT_EQ(clock::time_point(), gmp.LastUpdate()); | |
36 | } | |
37 | ||
38 | ///////////////////////////////////////////////// | |
39 | TEST(GaussMarkovProcessTest, Update) | |
40 | { | |
41 | // Start value of -1.2 | |
42 | // Theta (rate at which the process should approach the mean) of 1.0 | |
43 | // Mu (mean value) 2.5. | |
44 | // Sigma (volatility) of 0. | |
45 | GaussMarkovProcess gmp(-1.2, 1.0, 2.5, 0); | |
46 | EXPECT_DOUBLE_EQ(-1.2, gmp.Start()); | |
47 | EXPECT_DOUBLE_EQ(-1.2, gmp.Value()); | |
48 | EXPECT_DOUBLE_EQ(1.0, gmp.Theta()); | |
49 | EXPECT_DOUBLE_EQ(2.5, gmp.Mu()); | |
50 | EXPECT_DOUBLE_EQ(0.0, gmp.Sigma()); | |
51 | // EXPECT_EQ(clock::time_point(), gmp.LastUpdate()); | |
52 | ||
53 | clock::duration dt = std::chrono::milliseconds(100); | |
54 | ||
55 | // This process should steadily increase to the mean value of 2.5 since | |
56 | // there is no noise. | |
57 | for (int i = 0; i < 200; ++i) | |
58 | { | |
59 | double value = gmp.Update(dt); | |
60 | EXPECT_GT(value, -1.2); | |
61 | } | |
62 | ||
63 | EXPECT_NEAR(2.5, gmp.Value(), 1e-4); | |
64 | ||
65 | // The same should occur after a reset. | |
66 | gmp.Reset(); | |
67 | for (int i = 0; i < 200; ++i) | |
68 | { | |
69 | double value = gmp.Update(dt); | |
70 | EXPECT_GT(value, -1.2); | |
71 | } | |
72 | ||
73 | EXPECT_NEAR(2.5, gmp.Value(), 1e-4); | |
74 | } | |
75 | ||
76 | ///////////////////////////////////////////////// | |
77 | TEST(GaussMarkovProcessTest, Noise) | |
78 | { | |
79 | // Start value of 20.2 | |
80 | // Theta (rate at which the process should approach the mean) of 0.1 | |
81 | // Mu (mean value) 0. | |
82 | // Sigma (volatility) of 0.5. | |
83 | GaussMarkovProcess gmp(20.2, 0.1, 0, 0.5); | |
84 | clock::duration dt = std::chrono::milliseconds(100); | |
85 | Rand::Seed(1001); | |
86 | ||
87 | // This process should decrease toward the mean value of 0. With noise, | |
88 | // the process will walk. | |
89 | for (int i = 0; i < 1000; ++i) | |
90 | { | |
91 | double value = gmp.Update(dt); | |
92 | // Hand-tuned values that are repeatable given the seed set above. | |
93 | EXPECT_GT(value, -11); | |
94 | EXPECT_LT(value, 22); | |
95 | } | |
96 | // Hand-tuned values that are repeatable given the seed set above. | |
97 | #ifdef __APPLE__ | |
98 | EXPECT_NEAR(-4.960893, gmp.Value(), 1e-4); | |
99 | #elif _MSC_VER | |
100 | EXPECT_NEAR(-4.960893, gmp.Value(), 1e-4); | |
101 | #else | |
102 | EXPECT_NEAR(-4.118732, gmp.Value(), 1e-4); | |
103 | #endif | |
104 | } |
0 | # Copyright (C) 2020 Open Source Robotics Foundation | |
1 | # | |
2 | # Licensed under the Apache License, Version 2.0 (the "License") | |
3 | # you may not use this file except in compliance with the License. | |
4 | # You may obtain a copy of the License at | |
5 | # | |
6 | # http://www.apache.org/licenses/LICENSE-2.0 | |
7 | # | |
8 | # Unless required by applicable law or agreed to in writing, software | |
9 | # distributed under the License is distributed on an "AS IS" BASIS, | |
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
11 | # See the License for the specific language governing permissions and | |
12 | # limitations under the License. | |
13 | ||
14 | #!/usr/bin/env ruby | |
15 | ||
16 | require 'test/unit/ui/console/testrunner' | |
17 | require 'test/unit' | |
18 | require 'math' | |
19 | ||
20 | class GaussMarkovProcess_TEST < Test::Unit::TestCase | |
21 | def test_construction | |
22 | gmp = Ignition::Math::GaussMarkovProcess.new | |
23 | ||
24 | assert(gmp.Start() == 0.0, "Start value should equal zero") | |
25 | assert(gmp.Value() == 0.0, "Initial value should equal zero") | |
26 | assert(gmp.Theta() == 0.0, "Theta should equal zero") | |
27 | assert(gmp.Mu() == 0.0, "Mu should equal zero") | |
28 | assert(gmp.Sigma() == 0.0, "Sigma should equal zero") | |
29 | end | |
30 | ||
31 | def test_no_noise | |
32 | gmp = Ignition::Math::GaussMarkovProcess.new(-1.2, 1.0, 2.5, 0) | |
33 | assert(gmp.Start() == -1.2, "Start value should equal zero") | |
34 | assert(gmp.Value() == -1.2, "Initial value should equal zero") | |
35 | assert(gmp.Theta() == 1.0, "Theta should equal zero") | |
36 | assert(gmp.Mu() == 2.5, "Mu should equal zero") | |
37 | assert(gmp.Sigma() == 0.0, "Sigma should equal zero") | |
38 | ||
39 | for i in 0..200 do | |
40 | value = gmp.Update(0.1); | |
41 | assert(value > -1.2, "Value should be greater than -1.2") | |
42 | end | |
43 | ||
44 | assert(gmp.Value() >= 2.4999, "The final value should be near 2.5") | |
45 | assert(gmp.Value() <= 2.5, "The final value should be near 2.5") | |
46 | end | |
47 | ||
48 | def test_noise | |
49 | gmp = Ignition::Math::GaussMarkovProcess.new(20.2, 0.1, 0, 0.5) | |
50 | assert(gmp.Start() == 20.2, "Start value should equal zero") | |
51 | assert(gmp.Value() == 20.2, "Initial value should equal zero") | |
52 | assert(gmp.Theta() == 0.1, "Theta should equal zero") | |
53 | assert(gmp.Mu() == 0, "Mu should equal zero") | |
54 | assert(gmp.Sigma() == 0.5, "Sigma should equal zero") | |
55 | Ignition::Math::Rand::Seed(1001); | |
56 | ||
57 | for i in 0..1000 do | |
58 | value = gmp.Update(0.1); | |
59 | assert(value > -11, "Value should be greater than -10") | |
60 | assert(value < 22, "Value should be less than 25") | |
61 | end | |
62 | # Hand-tuned values that are repeatable given the seed set above. | |
63 | assert((gmp.Value() + 3.99148).abs <= 1e-4); | |
64 | end | |
65 | ||
66 | end | |
67 | ||
68 | exit Test::Unit::UI::Console::TestRunner.run(GaussMarkovProcess_TEST).passed? ? 0 : -1 |
101 | 101 | { |
102 | 102 | EXPECT_DOUBLE_EQ(math::fixnan(1.0 / 0.0), 0.0); |
103 | 103 | EXPECT_DOUBLE_EQ(math::fixnan(-1.0 / 0.0), 0.0); |
104 | EXPECT_DOUBLE_EQ(math::fixnan(0.0 / 0.0), 0.0); | |
104 | EXPECT_DOUBLE_EQ(math::fixnan(1.0 / 0.0), 0.0); | |
105 | 105 | |
106 | 106 | EXPECT_DOUBLE_EQ(math::fixnan(42.0), 42.0); |
107 | 107 | EXPECT_DOUBLE_EQ(math::fixnan(-42.0), -42.0); |
108 | 108 | |
109 | 109 | EXPECT_FLOAT_EQ(math::fixnan(1.0f / 0.0f), 0.0f); |
110 | 110 | EXPECT_FLOAT_EQ(math::fixnan(-1.0f / 0.0f), 0.0f); |
111 | EXPECT_FLOAT_EQ(math::fixnan(0.0f / 0.0f), 0.0f); | |
111 | EXPECT_FLOAT_EQ(math::fixnan(1.0f / 0.0f), 0.0f); | |
112 | 112 | |
113 | 113 | EXPECT_FLOAT_EQ(math::fixnan(42.0f), 42.0f); |
114 | 114 | EXPECT_FLOAT_EQ(math::fixnan(-42.0f), -42.0f); |
518 | 518 | } |
519 | 519 | |
520 | 520 | ///////////////////////////////////////////////// |
521 | TEST(HelpersTest, timePointToSecNsec) | |
522 | { | |
523 | std::pair<int64_t, int64_t> parts = math::timePointToSecNsec( | |
524 | math::secNsecToTimePoint(0, 0)); | |
525 | EXPECT_EQ(parts.first, 0); | |
526 | EXPECT_EQ(parts.second, 0); | |
527 | ||
528 | std::chrono::steady_clock::time_point point; | |
529 | point += std::chrono::nanoseconds(1000); | |
530 | parts = math::timePointToSecNsec(point); | |
531 | ||
532 | EXPECT_EQ(parts.first, 0); | |
533 | EXPECT_EQ(parts.second, 1000); | |
534 | ||
535 | point = math::secNsecToTimePoint(0, 0); | |
536 | point += std::chrono::seconds(60); | |
537 | point += std::chrono::nanoseconds(57989); | |
538 | parts = math::timePointToSecNsec(point); | |
539 | ||
540 | EXPECT_EQ(parts.first, 60); | |
541 | EXPECT_EQ(parts.second, 57989); | |
542 | } | |
543 | ||
544 | ///////////////////////////////////////////////// | |
545 | TEST(HelpersTest, secNsecToTimePoint) | |
546 | { | |
547 | using std::chrono::duration_cast; | |
548 | using std::chrono::nanoseconds; | |
549 | using std::chrono::steady_clock; | |
550 | ||
551 | std::chrono::steady_clock::time_point point = | |
552 | math::secNsecToTimePoint(0, 0); | |
553 | point += std::chrono::hours(24); | |
554 | ||
555 | std::chrono::steady_clock::time_point s = | |
556 | math::secNsecToTimePoint(24*60*60, 0); | |
557 | EXPECT_EQ(s, point); | |
558 | ||
559 | point = math::secNsecToTimePoint(0, 0); | |
560 | point += std::chrono::nanoseconds(1000); | |
561 | s = math::secNsecToTimePoint(0, 1000); | |
562 | EXPECT_EQ(s, point); | |
563 | } | |
564 | ||
565 | ///////////////////////////////////////////////// | |
566 | TEST(HelpersTest, timePointToString) | |
567 | { | |
568 | std::chrono::steady_clock::time_point time_clock = | |
569 | math::secNsecToTimePoint(0, 0); | |
570 | std::string s = math::timePointToString(time_clock); | |
571 | ||
572 | EXPECT_STREQ(s.c_str(), std::string("00 00:00:00.000").c_str()); | |
573 | ||
574 | std::chrono::steady_clock::time_point point; | |
575 | point += std::chrono::hours(24); | |
576 | ||
577 | s = math::timePointToString(point); | |
578 | EXPECT_STREQ(s.c_str(), std::string("01 00:00:00.000").c_str()); | |
579 | ||
580 | point = math::secNsecToTimePoint(0, 0); | |
581 | point += std::chrono::minutes(1); | |
582 | point += std::chrono::seconds(23); | |
583 | point += std::chrono::milliseconds(125); | |
584 | s = math::timePointToString(point); | |
585 | EXPECT_STREQ(s.c_str(), std::string("00 00:01:23.125").c_str()); | |
586 | } | |
587 | ||
588 | ///////////////////////////////////////////////// | |
589 | TEST(HelpersTest, durationToString) | |
590 | { | |
591 | std::chrono::steady_clock::duration duration = | |
592 | std::chrono::steady_clock::duration::zero(); | |
593 | std::string s = math::durationToString(duration); | |
594 | ||
595 | EXPECT_STREQ(s.c_str(), std::string("00 00:00:00.000").c_str()); | |
596 | ||
597 | std::chrono::steady_clock::duration duration1 = | |
598 | std::chrono::steady_clock::duration::zero(); | |
599 | duration1 += std::chrono::hours(24); | |
600 | ||
601 | s = math::durationToString(duration1); | |
602 | EXPECT_STREQ(s.c_str(), std::string("01 00:00:00.000").c_str()); | |
603 | ||
604 | duration1 = std::chrono::steady_clock::duration::zero();; | |
605 | duration1 += std::chrono::minutes(1); | |
606 | duration1 += std::chrono::seconds(23); | |
607 | duration1 += std::chrono::milliseconds(125); | |
608 | s = math::durationToString(duration1); | |
609 | EXPECT_STREQ(s.c_str(), std::string("00 00:01:23.125").c_str()); | |
610 | } | |
611 | ||
612 | ///////////////////////////////////////////////// | |
613 | TEST(HelpersTest, stringToDuration) | |
614 | { | |
615 | std::string time = "0 00:00:00.000"; | |
616 | std::chrono::steady_clock::duration resultTime = | |
617 | math::stringToDuration(time); | |
618 | std::chrono::steady_clock::duration duration = | |
619 | std::chrono::steady_clock::duration::zero(); | |
620 | ||
621 | EXPECT_EQ(resultTime, duration); | |
622 | ||
623 | time = "10 0"; | |
624 | resultTime = math::stringToDuration(time); | |
625 | duration = std::chrono::steady_clock::duration::zero(); | |
626 | duration += std::chrono::hours(10 * 24); | |
627 | ||
628 | EXPECT_EQ(resultTime, duration); | |
629 | ||
630 | time = "7"; | |
631 | resultTime = math::stringToDuration(time); | |
632 | duration = std::chrono::steady_clock::duration::zero(); | |
633 | duration += std::chrono::seconds(7); | |
634 | ||
635 | EXPECT_EQ(resultTime, duration); | |
636 | ||
637 | time = "7:10"; | |
638 | resultTime = math::stringToDuration(time); | |
639 | duration = std::chrono::steady_clock::duration::zero(); | |
640 | duration += std::chrono::minutes(7); | |
641 | duration += std::chrono::seconds(10); | |
642 | ||
643 | EXPECT_EQ(resultTime, duration); | |
644 | ||
645 | time = "17:10"; | |
646 | resultTime = math::stringToDuration(time); | |
647 | duration = std::chrono::steady_clock::duration::zero(); | |
648 | duration += std::chrono::minutes(17); | |
649 | duration += std::chrono::seconds(10); | |
650 | ||
651 | EXPECT_EQ(resultTime, duration); | |
652 | ||
653 | time = "7:10.4"; | |
654 | resultTime = math::stringToDuration(time); | |
655 | duration = std::chrono::steady_clock::duration::zero(); | |
656 | duration += std::chrono::minutes(7); | |
657 | duration += std::chrono::seconds(10); | |
658 | duration += std::chrono::milliseconds(400); | |
659 | ||
660 | EXPECT_EQ(resultTime, duration); | |
661 | ||
662 | time = "7:10.45"; | |
663 | resultTime = math::stringToDuration(time); | |
664 | duration = std::chrono::steady_clock::duration::zero(); | |
665 | duration += std::chrono::minutes(7); | |
666 | duration += std::chrono::seconds(10); | |
667 | duration += std::chrono::milliseconds(450); | |
668 | ||
669 | EXPECT_EQ(resultTime, duration); | |
670 | ||
671 | time = "7:10.456"; | |
672 | resultTime = math::stringToDuration(time); | |
673 | duration = std::chrono::steady_clock::duration::zero(); | |
674 | duration += std::chrono::minutes(7); | |
675 | duration += std::chrono::seconds(10); | |
676 | duration += std::chrono::milliseconds(456); | |
677 | ||
678 | EXPECT_EQ(resultTime, duration); | |
679 | ||
680 | time = "2 23:18:25.902"; | |
681 | resultTime = math::stringToDuration(time); | |
682 | duration = std::chrono::steady_clock::duration::zero(); | |
683 | duration += std::chrono::hours(2 * 24); | |
684 | duration += std::chrono::hours(23); | |
685 | duration += std::chrono::minutes(18); | |
686 | duration += std::chrono::seconds(25); | |
687 | duration += std::chrono::milliseconds(902); | |
688 | ||
689 | EXPECT_EQ(resultTime, duration); | |
690 | ||
691 | time = ".9"; | |
692 | resultTime = math::stringToDuration(time); | |
693 | duration = std::chrono::steady_clock::duration::zero(); | |
694 | duration += std::chrono::milliseconds(900); | |
695 | ||
696 | EXPECT_EQ(resultTime, duration); | |
697 | ||
698 | time = "bad time"; | |
699 | resultTime = math::stringToDuration(time); | |
700 | ||
701 | EXPECT_EQ(resultTime, std::chrono::steady_clock::duration::zero()); | |
702 | ||
703 | time = ""; | |
704 | resultTime = math::stringToDuration(time); | |
705 | ||
706 | EXPECT_EQ(resultTime, std::chrono::steady_clock::duration::zero()); | |
707 | ||
708 | time = "60"; | |
709 | resultTime = math::stringToDuration(time); | |
710 | ||
711 | EXPECT_EQ(resultTime, std::chrono::steady_clock::duration::zero()); | |
712 | ||
713 | time = "60:12"; | |
714 | resultTime = math::stringToDuration(time); | |
715 | ||
716 | EXPECT_EQ(resultTime, std::chrono::steady_clock::duration::zero()); | |
717 | ||
718 | time = "12:12.9999"; | |
719 | resultTime = math::stringToDuration(time); | |
720 | ||
721 | EXPECT_EQ(resultTime, std::chrono::steady_clock::duration::zero()); | |
722 | ||
723 | time = "25:12:12.99"; | |
724 | resultTime = math::stringToDuration(time); | |
725 | ||
726 | EXPECT_EQ(resultTime, std::chrono::steady_clock::duration::zero()); | |
727 | ||
728 | time = "999999999999999 5:12:12.5"; | |
729 | resultTime = math::stringToDuration(time); | |
730 | ||
731 | EXPECT_EQ(resultTime, std::chrono::steady_clock::duration::zero()); | |
732 | } | |
733 | ||
734 | ///////////////////////////////////////////////// | |
735 | TEST(HelpersTest, secNsecToDuration) | |
736 | { | |
737 | std::chrono::steady_clock::duration point = | |
738 | std::chrono::steady_clock::duration::zero(); | |
739 | point += std::chrono::hours(24); | |
740 | ||
741 | std::chrono::steady_clock::duration s = | |
742 | math::secNsecToDuration(24*60*60, 0); | |
743 | EXPECT_EQ(s, point); | |
744 | ||
745 | point = std::chrono::steady_clock::duration::zero(); | |
746 | point += std::chrono::nanoseconds(1000); | |
747 | s = math::secNsecToDuration(0, 1000); | |
748 | EXPECT_EQ(s, point); | |
749 | } | |
750 | ||
751 | ///////////////////////////////////////////////// | |
752 | TEST(HelpersTest, stringToTimePoint) | |
753 | { | |
754 | using namespace std::chrono_literals; | |
755 | ||
756 | std::chrono::steady_clock::time_point zeroTime{0s}; | |
757 | std::chrono::steady_clock::time_point negTime{-1s}; | |
758 | ||
759 | std::string time = "0 00:00:00.000"; | |
760 | std::chrono::steady_clock::time_point resultTime = | |
761 | math::stringToTimePoint(time); | |
762 | std::chrono::steady_clock::time_point point = zeroTime; | |
763 | ||
764 | EXPECT_EQ(resultTime, point); | |
765 | ||
766 | time = "10 0"; | |
767 | resultTime = math::stringToTimePoint(time); | |
768 | point = zeroTime; | |
769 | point += std::chrono::hours(10 * 24); | |
770 | ||
771 | EXPECT_EQ(resultTime, point); | |
772 | ||
773 | time = "7"; | |
774 | resultTime = math::stringToTimePoint(time); | |
775 | point = zeroTime; | |
776 | point += std::chrono::seconds(7); | |
777 | ||
778 | EXPECT_EQ(resultTime, point); | |
779 | ||
780 | time = "7:10"; | |
781 | resultTime = math::stringToTimePoint(time); | |
782 | point = zeroTime; | |
783 | point += std::chrono::minutes(7); | |
784 | point += std::chrono::seconds(10); | |
785 | ||
786 | EXPECT_EQ(resultTime, point); | |
787 | ||
788 | time = "17:10"; | |
789 | resultTime = math::stringToTimePoint(time); | |
790 | point = zeroTime; | |
791 | point += std::chrono::minutes(17); | |
792 | point += std::chrono::seconds(10); | |
793 | ||
794 | EXPECT_EQ(resultTime, point); | |
795 | ||
796 | time = "7:10.4"; | |
797 | resultTime = math::stringToTimePoint(time); | |
798 | point = zeroTime; | |
799 | point += std::chrono::minutes(7); | |
800 | point += std::chrono::seconds(10); | |
801 | point += std::chrono::milliseconds(400); | |
802 | ||
803 | EXPECT_EQ(resultTime, point); | |
804 | ||
805 | time = "7:10.45"; | |
806 | resultTime = math::stringToTimePoint(time); | |
807 | point = zeroTime; | |
808 | point += std::chrono::minutes(7); | |
809 | point += std::chrono::seconds(10); | |
810 | point += std::chrono::milliseconds(450); | |
811 | ||
812 | EXPECT_EQ(resultTime, point); | |
813 | ||
814 | time = "7:10.456"; | |
815 | resultTime = math::stringToTimePoint(time); | |
816 | point = zeroTime; | |
817 | point += std::chrono::minutes(7); | |
818 | point += std::chrono::seconds(10); | |
819 | point += std::chrono::milliseconds(456); | |
820 | ||
821 | EXPECT_EQ(resultTime, point); | |
822 | ||
823 | time = "2 23:18:25.902"; | |
824 | resultTime = math::stringToTimePoint(time); | |
825 | point = zeroTime; | |
826 | point += std::chrono::hours(2 * 24); | |
827 | point += std::chrono::hours(23); | |
828 | point += std::chrono::minutes(18); | |
829 | point += std::chrono::seconds(25); | |
830 | point += std::chrono::milliseconds(902); | |
831 | ||
832 | EXPECT_EQ(resultTime, point); | |
833 | ||
834 | time = ".9"; | |
835 | resultTime = math::stringToTimePoint(time); | |
836 | point = zeroTime; | |
837 | point += std::chrono::milliseconds(900); | |
838 | ||
839 | EXPECT_EQ(resultTime, point); | |
840 | ||
841 | time = "bad time"; | |
842 | resultTime = math::stringToTimePoint(time); | |
843 | ||
844 | EXPECT_EQ(resultTime, negTime); | |
845 | ||
846 | time = ""; | |
847 | resultTime = math::stringToTimePoint(time); | |
848 | ||
849 | EXPECT_EQ(resultTime, negTime); | |
850 | ||
851 | time = "60"; | |
852 | resultTime = math::stringToTimePoint(time); | |
853 | ||
854 | EXPECT_EQ(resultTime, negTime); | |
855 | ||
856 | time = "60:12"; | |
857 | resultTime = math::stringToTimePoint(time); | |
858 | ||
859 | EXPECT_EQ(resultTime, negTime); | |
860 | ||
861 | time = "12:12.9999"; | |
862 | resultTime = math::stringToTimePoint(time); | |
863 | ||
864 | EXPECT_EQ(resultTime, negTime); | |
865 | ||
866 | time = "25:12:12.99"; | |
867 | resultTime = math::stringToTimePoint(time); | |
868 | ||
869 | EXPECT_EQ(resultTime, negTime); | |
870 | ||
871 | time = "999999999999999 5:12:12.5"; | |
872 | resultTime = math::stringToTimePoint(time); | |
873 | ||
874 | EXPECT_EQ(resultTime, negTime); | |
875 | } | |
876 | ||
877 | ///////////////////////////////////////////////// | |
521 | 878 | TEST(HelpersTest, durationToSecNsec) |
522 | 879 | { |
523 | 880 | std::pair<int64_t, int64_t> parts; |
475 | 475 | EXPECT_TRUE(trueCubeMM3.SetFromBox(8*mass, 2*size)); |
476 | 476 | EXPECT_EQ(addedCube, math::Inertiald(trueCubeMM3, math::Pose3d::Zero)); |
477 | 477 | } |
478 | ||
479 | // Add two cubes with diagonal corners touching at one point | |
480 | // ┌---------┐ | |
481 | // | | | |
482 | // | | | |
483 | // | | | |
484 | // | | | |
485 | // ┌---------+---------┘ | |
486 | // | | | |
487 | // | | | |
488 | // | | | |
489 | // | | | |
490 | // └---------┘ | |
491 | { | |
492 | // properties of each cube to be added | |
493 | // side length: 1 | |
494 | // mass: 6 | |
495 | // diagonal moment of inertia values: 1 | |
496 | // off-diagonal moment of inertia values: 0 | |
497 | const double mass = 6.0; | |
498 | const math::Vector3d size(1, 1, 1); | |
499 | math::MassMatrix3d cubeMM3; | |
500 | EXPECT_TRUE(cubeMM3.SetFromBox(mass, size)); | |
501 | EXPECT_EQ( | |
502 | ignition::math::Vector3d::One, | |
503 | cubeMM3.DiagonalMoments()); | |
504 | EXPECT_EQ( | |
505 | ignition::math::Vector3d::Zero, | |
506 | cubeMM3.OffDiagonalMoments()); | |
507 | ||
508 | const math::Inertiald diagonalCubes = | |
509 | math::Inertiald(cubeMM3, math::Pose3d(-0.5, -0.5, -0.5, 0, 0, 0)) + | |
510 | math::Inertiald(cubeMM3, math::Pose3d(0.5, 0.5, 0.5, 0, 0, 0)); | |
511 | ||
512 | // lumped mass = 6 + 6 = 12 | |
513 | // lumped center of mass at (0, 0, 0) | |
514 | // lumped Moment of inertia: | |
515 | // for each cube | |
516 | // [ 1 0 0 ] [ 0.5^2 + 0.5^2 -0.5*0.5 -0.5*0.5 ] | |
517 | // [ 0 1 0 ] + 6 * [ -0.5*0.5 0.5^2 + 0.5^2 -0.5*0.5 ] | |
518 | // [ 0 0 1 ] [ -0.5*0.5 -0.5*0.5 0.5^2 + 0.5^2 ] | |
519 | // | |
520 | // [ 1 0 0 ] [ 0.5 -0.25 -0.25 ] | |
521 | // [ 0 1 0 ] + 6 * [ -0.25 0.5 -0.25 ] | |
522 | // [ 0 0 1 ] [ -0.25 -0.25 0.5 ] | |
523 | // | |
524 | // [ 1 0 0 ] [ 3.0 -1.5 -1.5 ] | |
525 | // [ 0 1 0 ] + [ -1.5 3.0 -1.5 ] | |
526 | // [ 0 0 1 ] [ -1.5 -1.5 3.0 ] | |
527 | // | |
528 | // [ 4.0 -1.5 -1.5 ] | |
529 | // [ -1.5 4.0 -1.5 ] | |
530 | // [ -1.5 -1.5 4.0 ] | |
531 | // | |
532 | // then double it to account for both cubes | |
533 | EXPECT_EQ(ignition::math::Pose3d::Zero, diagonalCubes.Pose()); | |
534 | EXPECT_DOUBLE_EQ(mass * 2.0, diagonalCubes.MassMatrix().Mass()); | |
535 | EXPECT_EQ( | |
536 | ignition::math::Vector3d(8, 8, 8), | |
537 | diagonalCubes.MassMatrix().DiagonalMoments()); | |
538 | EXPECT_EQ( | |
539 | ignition::math::Vector3d(-3, -3, -3), | |
540 | diagonalCubes.MassMatrix().OffDiagonalMoments()); | |
541 | } | |
478 | 542 | } |
479 | 543 | |
480 | 544 | ///////////////////////////////////////////////// |
14 | 14 | * |
15 | 15 | */ |
16 | 16 | |
17 | #include <ignition/math/Kmeans.hh> | |
18 | ||
17 | 19 | #include <iostream> |
18 | #include <ignition/math/Kmeans.hh> | |
20 | ||
19 | 21 | #include <ignition/math/Rand.hh> |
20 | 22 | #include "KmeansPrivate.hh" |
21 | 23 | |
146 | 148 | this->dataPtr->sums[i] / this->dataPtr->counters[i]; |
147 | 149 | } |
148 | 150 | } |
149 | while (changed > (this->dataPtr->obs.size() >> 10)); | |
151 | while (changed > (this->dataPtr->obs.size() >> 10)); // NOLINT | |
150 | 152 | |
151 | 153 | _centroids = this->dataPtr->centroids; |
152 | 154 | _labels = this->dataPtr->labels; |
20 | 20 | #include "ignition/math/Pose3.hh" |
21 | 21 | |
22 | 22 | using namespace ignition; |
23 | ||
24 | ///////////////////////////////////////////////// | |
25 | TEST(PoseTest, Construction) | |
26 | { | |
27 | math::Pose3d pose(1, 0, 0, 0, 0, 0); | |
28 | ||
29 | // Copy constructor | |
30 | math::Pose3d pose2(pose); | |
31 | EXPECT_EQ(pose2, pose); | |
32 | ||
33 | // Copy operator | |
34 | math::Pose3d pose3; | |
35 | pose3 = pose; | |
36 | EXPECT_EQ(pose3, pose); | |
37 | ||
38 | // Move constructor | |
39 | math::Pose3d pose4(std::move(pose)); | |
40 | EXPECT_EQ(pose4, pose2); | |
41 | pose = pose4; | |
42 | EXPECT_EQ(pose, pose2); | |
43 | ||
44 | // Move operator | |
45 | math::Pose3d pose5; | |
46 | pose5 = std::move(pose2); | |
47 | EXPECT_EQ(pose5, pose3); | |
48 | pose2 = pose5; | |
49 | EXPECT_EQ(pose2, pose3); | |
50 | ||
51 | // Inequality | |
52 | math::Pose3d pose6; | |
53 | EXPECT_NE(pose6, pose3); | |
54 | } | |
23 | 55 | |
24 | 56 | ///////////////////////////////////////////////// |
25 | 57 | TEST(PoseTest, Pose) |
139 | 171 | ///////////////////////////////////////////////// |
140 | 172 | TEST(PoseTest, ConstPose) |
141 | 173 | { |
142 | const math::Pose3d pose(0, 1, 2, 0, 0, 0); | |
174 | const math::Pose3d pose(0, 1, 2, 1, 0, 0); | |
143 | 175 | |
144 | 176 | EXPECT_TRUE(pose.Pos() == math::Vector3d(0, 1, 2)); |
145 | EXPECT_TRUE(pose.Rot() == math::Quaterniond(0, 0, 0)); | |
177 | EXPECT_TRUE(pose.Rot() == math::Quaterniond(1, 0, 0)); | |
146 | 178 | } |
147 | 179 | |
148 | 180 | ///////////////////////////////////////////////// |
154 | 186 | EXPECT_EQ(stream.str(), "0.1 1.2 2.3 0 0.1 1"); |
155 | 187 | } |
156 | 188 | |
189 | ///////////////////////////////////////////////// | |
190 | TEST(PoseTest, MutablePose) | |
191 | { | |
192 | math::Pose3d pose(0, 1, 2, 0, 0, 0); | |
193 | ||
194 | EXPECT_TRUE(pose.Pos() == math::Vector3d(0, 1, 2)); | |
195 | EXPECT_TRUE(pose.Rot() == math::Quaterniond(0, 0, 0)); | |
196 | ||
197 | pose.Pos() = math::Vector3d(10, 20, 30); | |
198 | pose.Rot() = math::Quaterniond(1, 2, 1); | |
199 | ||
200 | EXPECT_TRUE(pose.Pos() == math::Vector3d(10, 20, 30)); | |
201 | EXPECT_TRUE(pose.Rot() == math::Quaterniond(1, 2, 1)); | |
202 | } | |
203 | ||
204 | ///////////////////////////////////////////////// | |
205 | TEST(PoseTest, ConstPoseElements) | |
206 | { | |
207 | const math::Pose3d pose(0, 1, 2, 1, 1, 2); | |
208 | EXPECT_DOUBLE_EQ(pose.X(), 0); | |
209 | EXPECT_DOUBLE_EQ(pose.Y(), 1); | |
210 | EXPECT_DOUBLE_EQ(pose.Z(), 2); | |
211 | EXPECT_DOUBLE_EQ(pose.Roll(), 1); | |
212 | EXPECT_DOUBLE_EQ(pose.Pitch(), 1); | |
213 | EXPECT_DOUBLE_EQ(pose.Yaw(), 2); | |
214 | } | |
215 | ||
216 | ///////////////////////////////////////////////// | |
217 | TEST(PoseTest, SetPoseElements) | |
218 | { | |
219 | math::Pose3d pose(1, 2, 3, 1.57, 1, 2); | |
220 | EXPECT_DOUBLE_EQ(pose.X(), 1); | |
221 | EXPECT_DOUBLE_EQ(pose.Y(), 2); | |
222 | EXPECT_DOUBLE_EQ(pose.Z(), 3); | |
223 | ||
224 | pose.SetX(10); | |
225 | pose.SetY(12); | |
226 | pose.SetZ(13); | |
227 | ||
228 | EXPECT_DOUBLE_EQ(pose.X(), 10); | |
229 | EXPECT_DOUBLE_EQ(pose.Y(), 12); | |
230 | EXPECT_DOUBLE_EQ(pose.Z(), 13); | |
231 | } |
26 | 26 | using namespace ignition; |
27 | 27 | |
28 | 28 | ///////////////////////////////////////////////// |
29 | TEST(QuaternionTest, Construction) | |
30 | { | |
31 | math::Quaterniond q(0, 0, 0, 1); | |
32 | ||
33 | // Copy constructor | |
34 | math::Quaterniond q2(q); | |
35 | EXPECT_EQ(q2, q); | |
36 | ||
37 | // Copy operator | |
38 | math::Quaterniond q3; | |
39 | q3 = q; | |
40 | EXPECT_EQ(q3, q); | |
41 | ||
42 | // Move constructor | |
43 | math::Quaterniond q4(std::move(q)); | |
44 | EXPECT_EQ(q4, q2); | |
45 | q = q4; | |
46 | EXPECT_EQ(q, q2); | |
47 | ||
48 | // Move operator | |
49 | math::Quaterniond q5; | |
50 | q5 = std::move(q2); | |
51 | EXPECT_EQ(q5, q3); | |
52 | q2 = q5; | |
53 | EXPECT_EQ(q2, q3); | |
54 | ||
55 | // Inequality | |
56 | math::Quaterniond q6; | |
57 | EXPECT_NE(q6, q3); | |
58 | } | |
59 | ||
60 | ///////////////////////////////////////////////// | |
29 | 61 | TEST(QuaternionTest, Unit) |
30 | 62 | { |
31 | 63 | math::Quaterniond q; |
211 | 243 | } |
212 | 244 | |
213 | 245 | ///////////////////////////////////////////////// |
214 | TEST(QuaternionTest, Math) | |
246 | TEST(QuaternionTest, MathLog) | |
215 | 247 | { |
216 | 248 | math::Quaterniond q(IGN_PI*0.1, IGN_PI*0.5, IGN_PI); |
217 | EXPECT_TRUE(q == math::Quaterniond(0.110616, -0.698401, 0.110616, 0.698401)); | |
218 | ||
219 | EXPECT_TRUE(q.Log() == | |
220 | math::Quaterniond(0, -1.02593, 0.162491, 1.02593)); | |
221 | ||
222 | EXPECT_TRUE(q.Exp() == | |
223 | math::Quaterniond(0.545456, -0.588972, 0.093284, 0.588972)); | |
249 | ||
250 | EXPECT_EQ(q.Log(), math::Quaterniond(0, -1.02593, 0.162491, 1.02593)); | |
224 | 251 | |
225 | 252 | math::Quaterniond q1 = q; |
226 | 253 | q1.W(2.0); |
227 | EXPECT_TRUE(q1.Log() == | |
228 | math::Quaterniond(0, -0.698401, 0.110616, 0.698401)); | |
229 | ||
254 | EXPECT_EQ(q1.Log(), math::Quaterniond(0, -0.698401, 0.110616, 0.698401)); | |
255 | } | |
256 | ||
257 | ///////////////////////////////////////////////// | |
258 | TEST(QuaternionTest, MathExp) | |
259 | { | |
260 | math::Quaterniond q(IGN_PI*0.1, IGN_PI*0.5, IGN_PI); | |
261 | ||
262 | EXPECT_EQ(q.Exp(), | |
263 | math::Quaterniond(0.545456, -0.588972, 0.093284, 0.588972)); | |
264 | ||
265 | math::Quaterniond q1 = q; | |
230 | 266 | q1.X(0.000000001); |
231 | 267 | q1.Y(0.0); |
232 | 268 | q1.Z(0.0); |
233 | 269 | q1.W(0.0); |
234 | EXPECT_TRUE(q1.Exp() == math::Quaterniond(1, 0, 0, 0)); | |
270 | EXPECT_EQ(q1.Exp(), math::Quaterniond(1, 0, 0, 0)); | |
271 | } | |
272 | ||
273 | ///////////////////////////////////////////////// | |
274 | TEST(QuaternionTest, MathInvert) | |
275 | { | |
276 | math::Quaterniond q(IGN_PI*0.1, IGN_PI*0.5, IGN_PI); | |
235 | 277 | |
236 | 278 | q.Invert(); |
237 | EXPECT_TRUE(q == math::Quaterniond(0.110616, 0.698401, -0.110616, -0.698401)); | |
279 | EXPECT_EQ(q, math::Quaterniond(0.110616, 0.698401, -0.110616, -0.698401)); | |
280 | } | |
281 | ||
282 | ///////////////////////////////////////////////// | |
283 | TEST(QuaternionTest, MathAxis) | |
284 | { | |
285 | math::Quaterniond q(IGN_PI*0.1, IGN_PI*0.5, IGN_PI); | |
238 | 286 | |
239 | 287 | q.Axis(0, 1, 0, IGN_PI); |
240 | EXPECT_TRUE(q == math::Quaterniond(6.12303e-17, 0, 1, 0)); | |
288 | EXPECT_EQ(q, math::Quaterniond(6.12303e-17, 0, 1, 0)); | |
241 | 289 | |
242 | 290 | q.Axis(math::Vector3d(1, 0, 0), IGN_PI); |
243 | EXPECT_TRUE(q == math::Quaterniond(0, 1, 0, 0)); | |
291 | EXPECT_EQ(q, math::Quaterniond(0, 1, 0, 0)); | |
292 | } | |
293 | ||
294 | ///////////////////////////////////////////////// | |
295 | TEST(QuaternionTest, MathSet) | |
296 | { | |
297 | math::Quaterniond q(IGN_PI*0.1, IGN_PI*0.5, IGN_PI); | |
244 | 298 | |
245 | 299 | q.Set(1, 2, 3, 4); |
246 | 300 | EXPECT_TRUE(math::equal(q.W(), 1.0)); |
247 | 301 | EXPECT_TRUE(math::equal(q.X(), 2.0)); |
248 | 302 | EXPECT_TRUE(math::equal(q.Y(), 3.0)); |
249 | 303 | EXPECT_TRUE(math::equal(q.Z(), 4.0)); |
304 | } | |
305 | ||
306 | ///////////////////////////////////////////////// | |
307 | TEST(QuaternionTest, MathNormalized) | |
308 | { | |
309 | math::Quaterniond q(1, 2, 3, 4); | |
310 | ||
311 | math::Quaterniond q2 = q.Normalized(); | |
312 | EXPECT_EQ(q2, math::Quaterniond(0.182574, 0.365148, 0.547723, 0.730297)); | |
313 | } | |
314 | ||
315 | ///////////////////////////////////////////////// | |
316 | TEST(QuaternionTest, MathNormalize) | |
317 | { | |
318 | math::Quaterniond q(1, 2, 3, 4); | |
250 | 319 | |
251 | 320 | q.Normalize(); |
252 | EXPECT_TRUE(q == math::Quaterniond(0.182574, 0.365148, 0.547723, 0.730297)); | |
253 | ||
321 | EXPECT_EQ(q, math::Quaterniond(0.182574, 0.365148, 0.547723, 0.730297)); | |
322 | } | |
323 | ||
324 | ///////////////////////////////////////////////// | |
325 | TEST(QuaternionTest, Math) | |
326 | { | |
327 | math::Quaterniond q(IGN_PI*0.1, IGN_PI*0.5, IGN_PI); | |
328 | EXPECT_TRUE(q == math::Quaterniond(0.110616, -0.698401, 0.110616, 0.698401)); | |
329 | ||
330 | q.Set(1, 2, 3, 4); | |
331 | ||
332 | q.Normalize(); | |
254 | 333 | |
255 | 334 | EXPECT_TRUE(math::equal(q.Roll(), 1.4289, 1e-3)); |
256 | 335 | EXPECT_TRUE(math::equal(q.Pitch(), -0.339837, 1e-3)); |
511 | 590 | } |
512 | 591 | |
513 | 592 | ///////////////////////////////////////////////// |
514 | TEST(QuaterniondTest, From2Axes) | |
593 | TEST(QuaternionTest, From2Axes) | |
515 | 594 | { |
516 | 595 | math::Vector3d v1(1.0, 0.0, 0.0); |
517 | 596 | math::Vector3d v2(0.0, 1.0, 0.0); |
0 | /* | |
1 | * Copyright (C) 2020 Open Source Robotics Foundation | |
2 | * | |
3 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
4 | * you may not use this file except in compliance with the License. | |
5 | * You may obtain a copy of the License at | |
6 | * | |
7 | * http://www.apache.org/licenses/LICENSE-2.0 | |
8 | * | |
9 | * Unless required by applicable law or agreed to in writing, software | |
10 | * distributed under the License is distributed on an "AS IS" BASIS, | |
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 | * See the License for the specific language governing permissions and | |
13 | * limitations under the License. | |
14 | * | |
15 | */ | |
16 | ||
17 | %module rand | |
18 | %{ | |
19 | #include <ignition/math/Rand.hh> | |
20 | %} | |
21 | ||
22 | namespace ignition | |
23 | { | |
24 | namespace math | |
25 | { | |
26 | class Rand | |
27 | { | |
28 | public: static void Seed(unsigned int _seed); | |
29 | public: static unsigned int Seed(); | |
30 | public: static double DblUniform(double _min, double _max); | |
31 | public: static double DblNormal(double _mean, double _sigma); | |
32 | public: static int IntUniform(int _min, int _max); | |
33 | public: static int IntNormal(int _mean, int _sigma); | |
34 | }; | |
35 | } | |
36 | } |
0 | # Copyright (C) 2020 Open Source Robotics Foundation | |
1 | # | |
2 | # Licensed under the Apache License, Version 2.0 (the "License") | |
3 | # you may not use this file except in compliance with the License. | |
4 | # You may obtain a copy of the License at | |
5 | # | |
6 | # http://www.apache.org/licenses/LICENSE-2.0 | |
7 | # | |
8 | # Unless required by applicable law or agreed to in writing, software | |
9 | # distributed under the License is distributed on an "AS IS" BASIS, | |
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
11 | # See the License for the specific language governing permissions and | |
12 | # limitations under the License. | |
13 | ||
14 | #!/usr/bin/env ruby | |
15 | ||
16 | require 'test/unit/ui/console/testrunner' | |
17 | require 'test/unit' | |
18 | require 'math' | |
19 | ||
20 | class Rand_TEST < Test::Unit::TestCase | |
21 | def test_rand | |
22 | d = Ignition::Math::Rand::DblUniform(1, 2) | |
23 | assert(d >= 1 && d <= 2, "The value should be 1 <= d <= 2") | |
24 | ||
25 | i = Ignition::Math::Rand::IntUniform(1, 2) | |
26 | assert(i >= 1 && i <= 2, "The value should be 1 <= i <= 2") | |
27 | ||
28 | Ignition::Math::Rand::Seed(1001) | |
29 | ||
30 | i = Ignition::Math::Rand::IntNormal(10, 5) | |
31 | assert(i == 11, "The value should be 11") | |
32 | end | |
33 | end | |
34 | ||
35 | exit Test::Unit::UI::Console::TestRunner.run(Rand_TEST).passed? ? 0 : -1 |
15 | 15 | */ |
16 | 16 | |
17 | 17 | #include <numeric> |
18 | #include <limits> | |
18 | 19 | #include <deque> |
19 | 20 | #include "ignition/math/RollingMean.hh" |
20 | 21 |
93 | 93 | EXPECT_EQ(s.Interpolate(0, 0.5), |
94 | 94 | math::Quaterniond(0.987225, 0.077057, 0.11624, 0.077057)); |
95 | 95 | |
96 | math::Quaterniond q = s.Interpolate(1, 0.5); | |
97 | 96 | EXPECT_EQ(s.Interpolate(1, 0.5), |
98 | 97 | math::Quaterniond(0.987225, 0.077057, 0.11624, 0.077057)); |
99 | 98 | } |
66 | 66 | { |
67 | 67 | // Workaround to compare the two vector of vectors in MSVC 2013 |
68 | 68 | // and MSVC 2015. See |
69 | // https://bitbucket.org/ignitionrobotics/ign-math/issues/70 | |
69 | // https://github.com/ignitionrobotics/ign-math/issues/70 | |
70 | 70 | if (this->derivatives.size() != _other.derivatives.size()) |
71 | 71 | return false; |
72 | 72 |
45 | 45 | public: void Normalize(); |
46 | 46 | public: void Set(T _x, T _y); |
47 | 47 | public: T Dot(const Vector2<T> &_v) const; |
48 | public: Vector2 Abs() const; | |
49 | public: T AbsDot(const Vector2<T> &_v) const; | |
50 | public: inline void Correct(); | |
51 | public: void Max(const Vector2<T> &_v); | |
52 | public: void Min(const Vector2<T> &_v); | |
53 | public: T Max() const; | |
54 | public: T Min() const; | |
48 | 55 | public: Vector2 operator+(const Vector2 &_v) const; |
49 | 56 | public: inline Vector2<T> operator+(const T _s) const; |
50 | 57 | public: inline Vector2 operator-() const; |
23 | 23 | using namespace ignition; |
24 | 24 | |
25 | 25 | ///////////////////////////////////////////////// |
26 | TEST(Vector2Test, Construction) | |
27 | { | |
28 | math::Vector2d vec(1, 0); | |
29 | ||
30 | // Copy constructor | |
31 | math::Vector2d vec2(vec); | |
32 | EXPECT_EQ(vec2, vec); | |
33 | ||
34 | // Copy operator | |
35 | math::Vector2d vec3; | |
36 | vec3 = vec; | |
37 | EXPECT_EQ(vec3, vec); | |
38 | ||
39 | // Move constructor | |
40 | math::Vector2d vec4(std::move(vec)); | |
41 | EXPECT_EQ(vec4, vec2); | |
42 | vec = vec4; | |
43 | EXPECT_EQ(vec, vec2); | |
44 | ||
45 | // Move operator | |
46 | math::Vector2d vec5; | |
47 | vec5 = std::move(vec2); | |
48 | EXPECT_EQ(vec5, vec3); | |
49 | vec2 = vec5; | |
50 | EXPECT_EQ(vec2, vec3); | |
51 | ||
52 | // Inequality | |
53 | math::Vector2d vec6; | |
54 | EXPECT_NE(vec6, vec3); | |
55 | } | |
56 | ||
57 | ///////////////////////////////////////////////// | |
26 | 58 | TEST(Vector2Test, Vector2) |
27 | 59 | { |
28 | 60 | { |
43 | 75 | v.Normalize(); |
44 | 76 | EXPECT_TRUE(v == math::Vector2d(0.447214, 0.894427)); |
45 | 77 | |
78 | // ::Rounded | |
79 | v.Set(3.55, 8.49); | |
80 | EXPECT_TRUE(v.Rounded() == math::Vector2d(4, 8)); | |
81 | ||
82 | // ::Round | |
83 | v.Round(); | |
84 | EXPECT_TRUE(v == math::Vector2d(4, 8)); | |
85 | ||
46 | 86 | // ::Set |
47 | 87 | v.Set(4, 5); |
48 | 88 | EXPECT_TRUE(v == math::Vector2d(4, 5)); |
89 | ||
90 | // operator GetAbs | |
91 | v.Set(-1, -2); | |
92 | EXPECT_TRUE(v.Abs() == math::Vector2d(1, 2)); | |
49 | 93 | |
50 | 94 | // ::operator= |
51 | 95 | v = math::Vector2d(6, 7); |
111 | 155 | v.Set(10, 6); |
112 | 156 | v *= math::Vector2d(2, 4); |
113 | 157 | EXPECT_TRUE(v == math::Vector2d(20, 24)); |
114 | ||
115 | 158 | |
116 | 159 | // ::IsFinite |
117 | 160 | EXPECT_TRUE(v.IsFinite()); |
124 | 167 | } |
125 | 168 | |
126 | 169 | ///////////////////////////////////////////////// |
170 | TEST(Vector2Test, TestSum) | |
171 | { | |
172 | math::Vector2 vec1(0, 0); | |
173 | math::Vector2 vec2(1.0, 2.5); | |
174 | math::Vector2 vec3(-2, -4); | |
175 | ||
176 | int sum1 = vec1.Sum(); | |
177 | float sum2 = vec2.Sum(); | |
178 | int sum3 = vec3.Sum(); | |
179 | ||
180 | EXPECT_EQ(sum1, 0); | |
181 | EXPECT_FLOAT_EQ(sum2, 3.5); | |
182 | EXPECT_EQ(sum3, -6); | |
183 | } | |
184 | ||
185 | ///////////////////////////////////////////////// | |
186 | TEST(Vector2Test, TestNormalized) | |
187 | { | |
188 | math::Vector2d vec1(0, 0); | |
189 | math::Vector2d vec2(1, 2); | |
190 | ||
191 | math::Vector2d vec3 = vec1.Normalized(); | |
192 | ||
193 | // O zero vector should be equal to the normalized vector | |
194 | EXPECT_EQ(vec1, vec3); | |
195 | EXPECT_NE(vec2, vec3); | |
196 | ||
197 | vec3 = vec2.Normalized(); | |
198 | EXPECT_EQ(vec3, math::Vector2d(0.447213, 0.894427)); | |
199 | } | |
200 | ||
201 | ///////////////////////////////////////////////// | |
202 | TEST(Vector2Test, Max) | |
203 | { | |
204 | math::Vector2d vec1(0.1, 0.2); | |
205 | math::Vector2d vec2(0.3, 0.5); | |
206 | math::Vector2d vec3(0.4, 0.2); | |
207 | ||
208 | EXPECT_DOUBLE_EQ(vec1.Max(), 0.2); | |
209 | EXPECT_DOUBLE_EQ(vec3.Max(), 0.4); | |
210 | ||
211 | vec1.Max(vec2); | |
212 | EXPECT_EQ(vec1, math::Vector2d(0.3, 0.5)); | |
213 | ||
214 | vec1.Max(vec3); | |
215 | EXPECT_EQ(vec1, math::Vector2d(0.4, 0.5)); | |
216 | } | |
217 | ||
218 | ///////////////////////////////////////////////// | |
219 | TEST(Vector2Test, Min) | |
220 | { | |
221 | math::Vector2d vec1(0.3, 0.5); | |
222 | math::Vector2d vec2(0.1, 0.2); | |
223 | math::Vector2d vec3(0.05, 0.1); | |
224 | ||
225 | EXPECT_DOUBLE_EQ(vec1.Min(), 0.3); | |
226 | EXPECT_DOUBLE_EQ(vec3.Min(), 0.05); | |
227 | ||
228 | vec1.Min(vec2); | |
229 | EXPECT_EQ(vec1, math::Vector2d(0.1, 0.2)); | |
230 | ||
231 | vec1.Min(vec3); | |
232 | EXPECT_EQ(vec1, math::Vector2d(0.05, 0.1)); | |
233 | } | |
234 | ||
235 | ///////////////////////////////////////////////// | |
127 | 236 | TEST(Vector2Test, NoException) |
128 | 237 | { |
129 | 238 | math::Vector2d v(1, 2); |
156 | 265 | EXPECT_DOUBLE_EQ(v.Dot(math::Vector2d(0, 1)), 2.0); |
157 | 266 | } |
158 | 267 | |
268 | ////////////////////////////////////////////// | |
269 | TEST(Vector2Test, Correct) | |
270 | { | |
271 | math::Vector2d vec1(0, NAN); | |
272 | math::Vector2d vec2(INFINITY, -1); | |
273 | math::Vector2d vec3(10, -2); | |
274 | ||
275 | vec1.Correct(); | |
276 | vec2.Correct(); | |
277 | vec3.Correct(); | |
278 | ||
279 | EXPECT_EQ(vec1, math::Vector2d(0, 0)); | |
280 | EXPECT_EQ(vec2, math::Vector2d(0, -1)); | |
281 | EXPECT_EQ(vec3, math::Vector2d(10, -2)); | |
282 | } | |
283 | ||
284 | ///////////////////////////////////////////////// | |
285 | TEST(Vector2Test, AbsDot) | |
286 | { | |
287 | math::Vector2d v(1, -2); | |
288 | ||
289 | EXPECT_DOUBLE_EQ(v.AbsDot(math::Vector2d(3, 4)), 11.0); | |
290 | EXPECT_DOUBLE_EQ(v.AbsDot(math::Vector2d(0, 0)), 0.0); | |
291 | EXPECT_DOUBLE_EQ(v.AbsDot(math::Vector2d(1, 0)), 1.0); | |
292 | EXPECT_DOUBLE_EQ(v.AbsDot(math::Vector2d(0, 1)), 2.0); | |
293 | } | |
294 | ||
159 | 295 | ///////////////////////////////////////////////// |
160 | 296 | TEST(Vector2Test, OperatorStreamOut) |
161 | 297 | { |
166 | 302 | } |
167 | 303 | |
168 | 304 | ///////////////////////////////////////////////// |
169 | TEST(Vector2dTest, Add) | |
305 | TEST(Vector2Test, Add) | |
170 | 306 | { |
171 | 307 | math::Vector2d vec1(0.1, 0.2); |
172 | 308 | math::Vector2d vec2(1.1, 2.2); |
207 | 343 | } |
208 | 344 | |
209 | 345 | ///////////////////////////////////////////////// |
210 | TEST(Vector2dTest, Sub) | |
346 | TEST(Vector2Test, Sub) | |
211 | 347 | { |
212 | 348 | math::Vector2d vec1(0.1, 0.2); |
213 | 349 | math::Vector2d vec2(1.1, 2.2); |
285 | 421 | } |
286 | 422 | |
287 | 423 | ///////////////////////////////////////////////// |
288 | TEST(Vector2dTest, Length) | |
424 | TEST(Vector2Test, Length) | |
289 | 425 | { |
290 | 426 | // Zero vector |
291 | 427 | EXPECT_DOUBLE_EQ(math::Vector2d::Zero.Length(), 0.0); |
107 | 107 | "Zero should equal 1 with 1.1 tolerance") |
108 | 108 | end |
109 | 109 | |
110 | def test_max | |
111 | vec1 = Ignition::Math::Vector2d.new(0.1, 0.2) | |
112 | vec2 = Ignition::Math::Vector2d.new(0.3, 0.5) | |
113 | vec3 = Ignition::Math::Vector2d.new(0.4, 0.2) | |
114 | ||
115 | assert((vec1.Max() - 0.2).abs() < 1e-10, | |
116 | "Vector2 vec1.Max should equal 0.2") | |
117 | ||
118 | vec1.Max(vec2) | |
119 | assert(vec1 == Ignition::Math::Vector2d.new(0.3, 0.5), | |
120 | "Vector2 vec1 should equal [0.3, 0.5]") | |
121 | ||
122 | vec1.Max(vec3) | |
123 | assert(vec1 == Ignition::Math::Vector2d.new(0.4, 0.5), | |
124 | "Vector2 vec1 should equal [0.4, 0.5]") | |
125 | end | |
126 | ||
127 | def test_min | |
128 | vec1 = Ignition::Math::Vector2d.new(0.3, 0.5) | |
129 | vec2 = Ignition::Math::Vector2d.new(0.1, 0.2) | |
130 | vec3 = Ignition::Math::Vector2d.new(0.05, 0.1) | |
131 | ||
132 | assert((vec1.Min() - 0.3).abs() < 1e-10, | |
133 | "Vector2 vec1.Min should equal 0.3") | |
134 | ||
135 | vec1.Min(vec2) | |
136 | assert(vec1 == Ignition::Math::Vector2d.new(0.1, 0.2), | |
137 | "Vector2 vec1 should equal [0.1, 0.2]") | |
138 | ||
139 | vec3.Max(vec2) | |
140 | assert(vec3 == Ignition::Math::Vector2d.new(0.1, 0.2), | |
141 | "Vector2 vec3 should equal [0.1, 0.2]") | |
142 | end | |
143 | ||
110 | 144 | def test_dot |
111 | 145 | v = Ignition::Math::Vector2d.new(1, 2) |
112 | 146 |
16 | 16 | |
17 | 17 | #include <gtest/gtest.h> |
18 | 18 | |
19 | #include <numeric> | |
20 | #include <sstream> | |
21 | ||
19 | 22 | #include "ignition/math/Vector3.hh" |
20 | 23 | #include "ignition/math/Helpers.hh" |
21 | 24 | |
22 | 25 | using namespace ignition; |
23 | 26 | |
24 | 27 | ///////////////////////////////////////////////// |
25 | TEST(Vector3Test, Vector3d) | |
28 | TEST(Vector3dTest, Construction) | |
29 | { | |
30 | math::Vector3d vec(1, 0, 0); | |
31 | ||
32 | // Copy constructor | |
33 | math::Vector3d vec2(vec); | |
34 | EXPECT_EQ(vec2, vec); | |
35 | ||
36 | // Copy operator | |
37 | math::Vector3d vec3; | |
38 | vec3 = vec; | |
39 | EXPECT_EQ(vec3, vec); | |
40 | ||
41 | // Move constructor | |
42 | math::Vector3d vec4(std::move(vec)); | |
43 | EXPECT_EQ(vec4, vec2); | |
44 | vec = vec4; | |
45 | EXPECT_EQ(vec, vec2); | |
46 | ||
47 | // Move operator | |
48 | math::Vector3d vec5; | |
49 | vec5 = std::move(vec2); | |
50 | EXPECT_EQ(vec5, vec3); | |
51 | vec2 = vec5; | |
52 | EXPECT_EQ(vec2, vec3); | |
53 | ||
54 | // Inequality | |
55 | math::Vector3d vec6; | |
56 | EXPECT_NE(vec6, vec3); | |
57 | } | |
58 | ||
59 | ///////////////////////////////////////////////// | |
60 | TEST(Vector3dTest, Vector3d) | |
26 | 61 | { |
27 | 62 | math::Vector3d v; |
28 | 63 | |
386 | 421 | |
387 | 422 | ///////////////////////////////////////////////// |
388 | 423 | // Test Equal function with specified tolerance |
389 | TEST(Vector2Test, EqualTolerance) | |
424 | TEST(Vector3dTest, EqualTolerance) | |
390 | 425 | { |
391 | 426 | EXPECT_FALSE(math::Vector3d::Zero.Equal(math::Vector3d::One, 1e-6)); |
392 | 427 | EXPECT_FALSE(math::Vector3d::Zero.Equal(math::Vector3d::One, 1e-3)); |
413 | 448 | |
414 | 449 | EXPECT_NO_THROW(math::equal(v[3], 4.0)); |
415 | 450 | EXPECT_DOUBLE_EQ(v[3], 3.0); |
416 | } | |
417 | ||
451 | ||
452 | std::ostringstream ss; | |
453 | math::Vector3d vInf(0, 0, std::numeric_limits<double>::infinity()); | |
454 | EXPECT_NO_THROW(ss << vInf); | |
455 | } | |
456 |
0 | /* | |
1 | * Copyright (C) 2016 Open Source Robotics Foundation | |
2 | * | |
3 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
4 | * you may not use this file except in compliance with the License. | |
5 | * You may obtain a copy of the License at | |
6 | * | |
7 | * http://www.apache.org/licenses/LICENSE-2.0 | |
8 | * | |
9 | * Unless required by applicable law or agreed to in writing, software | |
10 | * distributed under the License is distributed on an "AS IS" BASIS, | |
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 | * See the License for the specific language governing permissions and | |
13 | * limitations under the License. | |
14 | * | |
15 | */ | |
16 | ||
17 | #ifdef SWIGRUBY | |
18 | %begin %{ | |
19 | #define HAVE_ISFINITE 1 | |
20 | %} | |
21 | #endif | |
22 | ||
23 | %module vector4 | |
24 | %{ | |
25 | #include <ignition/math/Vector4.hh> | |
26 | %} | |
27 | ||
28 | namespace ignition | |
29 | { | |
30 | namespace math | |
31 | { | |
32 | template<typename T> | |
33 | class Vector4 | |
34 | { | |
35 | public: static const Vector4 Zero; | |
36 | public: static const Vector4 One; | |
37 | public: Vector4(); | |
38 | public: Vector4(const T &_x, const T &_y, const T &_z, const T &_w); | |
39 | public: Vector4(const Vector4<T> &_v); | |
40 | public: virtual ~Vector4(); | |
41 | public: T Distance(const Vector4<T> &_pt) const; | |
42 | public: T Length() const; | |
43 | public: T SquaredLength() const; | |
44 | public: void Normalize(); | |
45 | public: inline void Set(T _x = 0, T _y = 0, T _z = 0, T _w = 0); | |
46 | public: Vector4 operator+(const Vector4<T> &_v) const; | |
47 | public: inline Vector4<T> operator+(const T _s) const; | |
48 | public: inline Vector4 operator-() const; | |
49 | public: inline Vector4<T> operator-(const Vector4<T> &_pt) const; | |
50 | public: inline Vector4<T> operator-(const T _s) const; | |
51 | public: const Vector4<T> operator/(const Vector4<T> &_pt) const; | |
52 | public: const Vector4<T> operator/(T _v) const; | |
53 | public: Vector4<T> operator*(const Vector4<T> &_p) const; | |
54 | public: inline Vector4<T> operator*(T _s) const; | |
55 | public: bool operator==(const Vector4<T> &_v) const; | |
56 | public: bool Equal(const Vector4 &_v, const T &_tol) const; | |
57 | public: bool IsFinite() const; | |
58 | public: inline T X() const; | |
59 | public: inline T Y() const; | |
60 | public: inline T Z() const; | |
61 | public: inline T W() const; | |
62 | public: inline void X(const T &_v); | |
63 | public: inline void Y(const T &_v); | |
64 | public: inline void Z(const T &_v); | |
65 | public: inline void W(const T &_v); | |
66 | }; | |
67 | ||
68 | %template(Vector4i) Vector4<int>; | |
69 | %template(Vector4d) Vector4<double>; | |
70 | %template(Vector4f) Vector4<float>; | |
71 | } | |
72 | } |
23 | 23 | using namespace ignition; |
24 | 24 | |
25 | 25 | ///////////////////////////////////////////////// |
26 | TEST(Vector4dTest, Construction) | |
27 | { | |
28 | math::Vector4d vec(1, 0, 0, 0); | |
29 | ||
30 | // Copy constructor | |
31 | math::Vector4d vec2(vec); | |
32 | EXPECT_EQ(vec2, vec); | |
33 | ||
34 | // Copy operator | |
35 | math::Vector4d vec3; | |
36 | vec3 = vec; | |
37 | EXPECT_EQ(vec3, vec); | |
38 | ||
39 | // Move constructor | |
40 | math::Vector4d vec4(std::move(vec)); | |
41 | EXPECT_EQ(vec4, vec2); | |
42 | vec = vec4; | |
43 | EXPECT_EQ(vec, vec2); | |
44 | ||
45 | // Move operator | |
46 | math::Vector4d vec5; | |
47 | vec5 = std::move(vec2); | |
48 | EXPECT_EQ(vec5, vec3); | |
49 | vec2 = vec5; | |
50 | EXPECT_EQ(vec2, vec3); | |
51 | ||
52 | // Inequality | |
53 | math::Vector4d vec6; | |
54 | EXPECT_NE(vec6, vec3); | |
55 | } | |
56 | ||
57 | ///////////////////////////////////////////////// | |
26 | 58 | TEST(Vector4dTest, Vector4d) |
27 | 59 | { |
28 | 60 | { |
42 | 74 | math::Vector4d v(v1); |
43 | 75 | EXPECT_EQ(v, v1); |
44 | 76 | |
77 | // ::Distance | |
45 | 78 | EXPECT_TRUE(math::equal(v.Distance( |
46 | 79 | math::Vector4d(0, 0, 0, 0)), 5.4772, 1e-3)); |
80 | EXPECT_TRUE(math::equal(v.Distance(1, 2, 3, 4), 0.0)); | |
47 | 81 | |
48 | 82 | // ::Length() |
49 | 83 | v.Set(1, 2, 3, 4); |
52 | 86 | // ::SquaredLength() |
53 | 87 | EXPECT_TRUE(math::equal(v.SquaredLength(), 30.0)); |
54 | 88 | |
89 | // ::Rounded | |
90 | v.Set(1.23, 2.34, 3.55, 8.49); | |
91 | EXPECT_TRUE(v.Rounded() == math::Vector4d(1, 2, 4, 8)); | |
92 | ||
93 | // ::Round | |
94 | v.Round(); | |
95 | EXPECT_TRUE(v == math::Vector4d(1, 2, 4, 8)); | |
96 | ||
97 | // ::Correct | |
98 | v.Set(1, 1, std::nan("1"), 1); | |
99 | v.Correct(); | |
100 | EXPECT_TRUE(v == math::Vector4d(1, 1, 0, 1)); | |
101 | ||
55 | 102 | // ::Normalize |
103 | v.Set(1, 2, 3, 4); | |
56 | 104 | v.Normalize(); |
57 | 105 | EXPECT_EQ(v, math::Vector4d(0.182574, 0.365148, 0.547723, 0.730297)); |
106 | ||
107 | // ::Normalized | |
108 | v.Set(1, 2, 3, 4); | |
109 | EXPECT_EQ(v.Normalized(), | |
110 | math::Vector4d(0.182574, 0.365148, 0.547723, 0.730297)); | |
58 | 111 | |
59 | 112 | // ::Set |
60 | 113 | v.Set(2, 4, 6, 8); |
61 | 114 | EXPECT_EQ(v, math::Vector4d(2, 4, 6, 8)); |
115 | ||
116 | // ::DotProd | |
117 | EXPECT_TRUE(math::equal(60.0, v.Dot(math::Vector4d(1, 2, 3, 4)), 1e-2)); | |
118 | ||
119 | // ::AbsDotProd | |
120 | v1.Set(-1, -2, -3, -4); | |
121 | EXPECT_TRUE(math::equal(60.0, v.AbsDot(v1), 1e-2)); | |
122 | ||
123 | // ::GetAbs | |
124 | EXPECT_TRUE(v1.Abs() == math::Vector4d(1, 2, 3, 4)); | |
125 | EXPECT_TRUE(v.Abs() == math::Vector4d(2, 4, 6, 8)); | |
62 | 126 | |
63 | 127 | // ::operator= vector4 |
64 | 128 | v = v1; |
127 | 191 | |
128 | 192 | // ::operator != vector4 |
129 | 193 | EXPECT_NE(v, math::Vector4d()); |
194 | ||
195 | // ::operator < vector4 | |
196 | v.Set(1, 2, 3, 4); | |
197 | EXPECT_TRUE(v < math::Vector4d(4, 3, 2, 1)); | |
130 | 198 | |
131 | 199 | // ::IsFinite |
132 | 200 | EXPECT_TRUE(v.IsFinite()); |
156 | 224 | } |
157 | 225 | |
158 | 226 | ///////////////////////////////////////////////// |
227 | TEST(Vector4dTest, Max) | |
228 | { | |
229 | math::Vector4d vec1(0.1, 0.2, 0.3, 0.2); | |
230 | math::Vector4d vec2(0.2, 0.3, 0.4, 0.3); | |
231 | math::Vector4d vec3(0.1, 0.2, 0.3, 0.4); | |
232 | ||
233 | EXPECT_DOUBLE_EQ(vec1.Max(), 0.3); | |
234 | ||
235 | vec1.Max(vec2); | |
236 | EXPECT_EQ(vec1, math::Vector4d(0.2, 0.3, 0.4, 0.3)); | |
237 | ||
238 | vec1.Max(vec3); | |
239 | EXPECT_EQ(vec1, math::Vector4d(0.2, 0.3, 0.4, 0.4)); | |
240 | } | |
241 | ||
242 | ///////////////////////////////////////////////// | |
243 | TEST(Vector4dTest, Min) | |
244 | { | |
245 | math::Vector4d vec1(0.1, 0.2, 0.3, 0.4); | |
246 | math::Vector4d vec2(0.2, 0.3, 0.4, 0.3); | |
247 | math::Vector4d vec3(0.05, 0.1, 0.2, 0.2); | |
248 | ||
249 | EXPECT_DOUBLE_EQ(vec1.Min(), 0.1); | |
250 | ||
251 | vec1.Min(vec2); | |
252 | EXPECT_EQ(vec1, math::Vector4d(0.1, 0.2, 0.3, 0.3)); | |
253 | ||
254 | vec1.Min(vec3); | |
255 | EXPECT_EQ(vec1, math::Vector4d(0.05, 0.1, 0.2, 0.2)); | |
256 | } | |
257 | ||
258 | ///////////////////////////////////////////////// | |
159 | 259 | // Test Equal function with specified tolerance |
160 | TEST(Vector2Test, EqualTolerance) | |
260 | TEST(Vector4dTest, EqualTolerance) | |
161 | 261 | { |
162 | 262 | EXPECT_FALSE(math::Vector4d::Zero.Equal(math::Vector4d::One, 1e-6)); |
163 | 263 | EXPECT_FALSE(math::Vector4d::Zero.Equal(math::Vector4d::One, 1e-3)); |
164 | 264 | EXPECT_FALSE(math::Vector4d::Zero.Equal(math::Vector4d::One, 1e-1)); |
165 | 265 | EXPECT_TRUE(math::Vector4d::Zero.Equal(math::Vector4d::One, 1)); |
166 | 266 | EXPECT_TRUE(math::Vector4d::Zero.Equal(math::Vector4d::One, 1.1)); |
267 | } | |
268 | ||
269 | ///////////////////////////////////////////////// | |
270 | TEST(Vector4dTest, Sum) | |
271 | { | |
272 | math::Vector4d vec1(1.5, 2.5, 3.5, -4.5); | |
273 | ||
274 | EXPECT_TRUE(math::equal(math::Vector4d::Zero.Sum(), 0.0, 1e-6)); | |
275 | EXPECT_TRUE(math::equal(math::Vector4d::One.Sum(), 4.0, 1e-6)); | |
276 | EXPECT_TRUE(math::equal(vec1.Sum(), 3.0, 1e-6)); | |
167 | 277 | } |
168 | 278 | |
169 | 279 | ///////////////////////////////////////////////// |
258 | 368 | } |
259 | 369 | |
260 | 370 | ///////////////////////////////////////////////// |
261 | TEST(Vector4Test, Multiply) | |
371 | TEST(Vector4dTest, Multiply) | |
262 | 372 | { |
263 | 373 | math::Vector4d v(0.1, -4.2, 11.1, 8.4); |
264 | 374 |
0 | # Copyright (C) 2016 Open Source Robotics Foundation | |
1 | # | |
2 | # Licensed under the Apache License, Version 2.0 (the "License"); | |
3 | # you may not use this file except in compliance with the License. | |
4 | # You may obtain a copy of the License at | |
5 | # | |
6 | # http://www.apache.org/licenses/LICENSE-2.0 | |
7 | # | |
8 | # Unless required by applicable law or agreed to in writing, software | |
9 | # distributed under the License is distributed on an "AS IS" BASIS, | |
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
11 | # See the License for the specific language governing permissions and | |
12 | # limitations under the License. | |
13 | ||
14 | #!/usr/bin/env ruby | |
15 | ||
16 | require 'test/unit/ui/console/testrunner' | |
17 | require 'test/unit' | |
18 | require 'math' | |
19 | ||
20 | ||
21 | class Vector4_TEST < Test::Unit::TestCase | |
22 | def test_construction | |
23 | v = Ignition::Math::Vector4d.new | |
24 | ||
25 | # ::operator== vector4 | |
26 | assert(true, | |
27 | "Vector4d::Zero should equal [0, 0, 0, 0]") | |
28 | ||
29 | # ::Distance, ::Length() | |
30 | v.Set(1, 2, 3, 4) | |
31 | assert(v.Length() == v.Distance(Ignition::Math::Vector4d.Zero), | |
32 | "Vector4d::Lenth() should equal Vector4d::Distance(zero)") | |
33 | ||
34 | # ::operator/ vector4 | |
35 | v.Set(4, 4, 4, 4) | |
36 | v = v / Ignition::Math::Vector4d.new(1, 2, 2, 4) | |
37 | assert(v == Ignition::Math::Vector4d.new(4, 2, 2, 1), | |
38 | "v / Vector4d(1, 2, 2, 4) should equal Vector4d(4, 2, 2, 1)") | |
39 | ||
40 | # ::operator / double | |
41 | v = v / 2 | |
42 | assert(v == Ignition::Math::Vector4d.new(2, 1, 1, 0.5), | |
43 | "v / 2 should equal Vector4d(2, 1, 1, .5)") | |
44 | ||
45 | # ::operator * vector4 | |
46 | v = v * Ignition::Math::Vector4d.new(2, 3, 3, 4) | |
47 | assert(v == Ignition::Math::Vector4d.new(4, 3, 3, 2), | |
48 | "v * Vector4d(2, 3, 3, 4) should equal Vector4d(4, 3, 3, 2)") | |
49 | ||
50 | # operator /= | |
51 | v.Set(1, 2, 2, 4) | |
52 | v /= Ignition::Math::Vector4d.new(1, 4, 8, 4) | |
53 | assert(v == Ignition::Math::Vector4d.new(1, 0.5, 0.25, 1)) | |
54 | ||
55 | # operator *= | |
56 | v.Set(1, 2, 2, 4) | |
57 | v *= Ignition::Math::Vector4d.new(2, 0.5, 0.25, 0.1) | |
58 | assert(v == Ignition::Math::Vector4d.new(2, 1, 0.5, 0.4)) | |
59 | ||
60 | # Test the static defines. | |
61 | assert(Ignition::Math::Vector4d.Zero == | |
62 | Ignition::Math::Vector4d.new(0, 0, 0, 0), | |
63 | "Vector4d::Zero should equal [0, 0, 0, 0]") | |
64 | ||
65 | assert(Ignition::Math::Vector4d.One == | |
66 | Ignition::Math::Vector4d.new(1, 1, 1, 1), | |
67 | "Vector4d::One should equal [1, 1, 1, 1]") | |
68 | end | |
69 | ||
70 | def test_distance | |
71 | vec1 = Ignition::Math::Vector4d.new(0, 0, 0, 0) | |
72 | vec2 = Ignition::Math::Vector4d.new(1, 2, 3, 4) | |
73 | ||
74 | dist = vec1.Distance(vec2) | |
75 | assert((dist - 5.47722557505).abs() < 1e-6, | |
76 | "Vector4 distance should be near 5,47722557505") | |
77 | end | |
78 | ||
79 | def test_squared_length | |
80 | vec1 = Ignition::Math::Vector4d.new(0, 0, 0, 0) | |
81 | vec2 = Ignition::Math::Vector4d.new(1, 2, 3, 4) | |
82 | ||
83 | sum1 = vec1.SquaredLength() | |
84 | sum2 = vec2.SquaredLength() | |
85 | ||
86 | assert(sum1 == 0, "Vector4 sum1 should equal 0") | |
87 | assert(sum2 == 30, "Vector4 sum2 should equal 30") | |
88 | end | |
89 | ||
90 | def test_length | |
91 | # Zero vector | |
92 | assert(Ignition::Math::Vector4d.Zero.Length() == 0.0, | |
93 | "Vector4 length of [0, 0, 0, 0] should equal 0") | |
94 | assert(Ignition::Math::Vector4d.Zero.SquaredLength() == 0.0, | |
95 | "Vector4 squared length of [0, 0, 0, 0] should equal 0") | |
96 | ||
97 | # One vector | |
98 | assert((Ignition::Math::Vector4d.One.Length() - | |
99 | Math.sqrt(4.0)).abs() < 1e-10, | |
100 | "Vector4 length of [1, 1, 1, 1] should equal sqrt(4.0)") | |
101 | ||
102 | assert(Ignition::Math::Vector4d.One.SquaredLength() == 4.0, | |
103 | "Vector4 squared lenght of [1, 1, 1, 1] should equal 4.0") | |
104 | ||
105 | # Arbitrary vector | |
106 | v = Ignition::Math::Vector4d.new(0.1, -4.2, 2.5, -1.2) | |
107 | assert((v.Length() - 5.03388517946).abs() < 1e-10, | |
108 | "Vector4 v length should equal 5.03388517946") | |
109 | ||
110 | assert((v.SquaredLength() - 25.34).abs() < 1e-10 , | |
111 | "Vector4 v squared length should equal 25.34") | |
112 | end | |
113 | ||
114 | def test_normalize | |
115 | vec1 = Ignition::Math::Vector4d.new(0, 0, 0, 0) | |
116 | vec2 = Ignition::Math::Vector4d.new(1, 2, 3, 4) | |
117 | ||
118 | vec3 = vec1 | |
119 | vec3.Normalize() | |
120 | assert(vec3 == vec1, "Vector4 vec3 should equal vec1") | |
121 | assert(vec1 == Ignition::Math::Vector4d.Zero, | |
122 | "Vector4 should equal [0, 0, 0, 0]") | |
123 | ||
124 | vec3 = vec2 | |
125 | vec2.Normalize() | |
126 | assert(vec2.Equal(Ignition::Math::Vector4d.new(0.182575, 0.365150, 0.547725, 0.730300), 1e-5), | |
127 | "Vector4 vec3 should equal [0.182575, 0.365150, 0.547725, 0.730300]") | |
128 | end | |
129 | ||
130 | def test_add | |
131 | vec1 = Ignition::Math::Vector4d.new(0.1, 0.2, 0.4, 0.8) | |
132 | vec2 = Ignition::Math::Vector4d.new(1.1, 2.2, 3.4, 4.3) | |
133 | ||
134 | vec3 = vec1 | |
135 | vec3 += vec2 | |
136 | ||
137 | assert(vec1 + vec2 == Ignition::Math::Vector4d.new(1.2, 2.4, 3.8, 5.1), | |
138 | "Vector4 vec1 + vec2 should equal [1.2, 2.4, 3.8, 4.9]") | |
139 | assert(vec3 == Ignition::Math::Vector4d.new(1.2, 2.4, 3.8, 5.1), | |
140 | "Vector4 vec3 should equal [1.2, 2.4, 3.8, 4.9]") | |
141 | ||
142 | # Addition with zeros | |
143 | ||
144 | # Scalar left and right | |
145 | assert(vec1 + 0 == vec1, "Vector4 vec1+0 should equal vec1") | |
146 | ||
147 | # Vector left and right | |
148 | assert(Ignition::Math::Vector4d.Zero + vec1 == vec1, | |
149 | "Vector4 Zero + vec1 should equal vec1") | |
150 | assert(vec1 + Ignition::Math::Vector4d.Zero == vec1, | |
151 | "Vector4 vec1 + Zero should equal vec1") | |
152 | ||
153 | # Addition assignment | |
154 | vec4 = vec1 | |
155 | vec4 += 0 | |
156 | assert(vec4 == vec1, "Vector4 vec4 should equal vec1") | |
157 | vec4 += Ignition::Math::Vector4d.Zero | |
158 | assert(vec4 == vec1, "Vector4 vec4 should equal vec1") | |
159 | ||
160 | # Add non-trivial scalar values left and right | |
161 | assert(vec1 + 2.5 == Ignition::Math::Vector4d.new(2.6, 2.7, 2.9, 3.3), | |
162 | "Vector4 vec1 + 2.5 should equal [2.6, 2.7, 2.9, 3.3]") | |
163 | ||
164 | vec1 = vec4 | |
165 | vec4 += 2.5 | |
166 | assert(vec4 == Ignition::Math::Vector4d.new(2.6, 2.7, 2.9, 3.3), | |
167 | "Vector4 vec4 should equal [2.6, 2.7, 2.9, 3.3]") | |
168 | end | |
169 | ||
170 | def test_sub | |
171 | vec1 = Ignition::Math::Vector4d.new(0.1, 0.2, 0.4, 0.8) | |
172 | vec2 = Ignition::Math::Vector4d.new(1.1, 2.2, 3.4, 4.3) | |
173 | ||
174 | vec3 = vec2 | |
175 | vec3 -= vec1 | |
176 | ||
177 | assert(vec2 - vec1 === Ignition::Math::Vector4d.new(1.0, 2.0, 3.0, 3.5), | |
178 | "Vector4 vec2 - vec1 should equal [1.0, 2.0, 3.0, 3.5]") | |
179 | assert(vec3 == Ignition::Math::Vector4d.new(1.0, 2.0, 3.0, 3.5), | |
180 | "Vector4 vec3 should equal [1.0, 2.0, 3.0, 3.5]") | |
181 | ||
182 | # Subtraction with zeros | |
183 | ||
184 | # Scalar left and right | |
185 | assert(vec1 - 0 == vec1, "Vector4 vec1 - 0 should equal vec1") | |
186 | ||
187 | # Vector left and right | |
188 | assert(Ignition::Math::Vector4d.Zero - vec1 == -vec1, | |
189 | "Vector4 Zero - vec1 should equal -vec1") | |
190 | assert(vec1 - Ignition::Math::Vector4d.Zero == vec1, | |
191 | "Vector4 vec1 - Zero should equal vec1") | |
192 | ||
193 | # Subtraction assignment | |
194 | vec4 = vec1 | |
195 | vec4 -= 0 | |
196 | assert(vec4 == vec1, "Vector4 vec4 should equal vec1") | |
197 | vec4 -= Ignition::Math::Vector4d.Zero | |
198 | assert(vec4 == vec1, "Vector4 vec4 should equal vec1") | |
199 | ||
200 | # Subtract non-trivial scalar values left and right | |
201 | assert(vec1 - 2.5 == -Ignition::Math::Vector4d.new(2.4, 2.3, 2.1, 1.7), | |
202 | "Vecetor3 vec1 - 2.5 should equal [2.4, 2.3, 2.1, 1.7]") | |
203 | ||
204 | vec4 = vec1 | |
205 | vec4 -= 2.5 | |
206 | assert(vec4 == -Ignition::Math::Vector4d.new(2.4, 2.3, 2.1, 1.7), | |
207 | "Vector4 vec4 - 2.5 should equal [2.4, 2.3, 2.1, 1.7]") | |
208 | end | |
209 | ||
210 | def test_divide | |
211 | vec1 = Ignition::Math::Vector4d.new(0.1, 0.2, 0.4, 0.8) | |
212 | ||
213 | vec3 = vec1 / 2.0 | |
214 | assert(vec3 == Ignition::Math::Vector4d.new(0.05, 0.1, 0.2, 0.4), | |
215 | "Vector4 vec3 should equal [0.05, 0.1, 0.2, 0.4]") | |
216 | ||
217 | vec3 /= 4.0 | |
218 | assert(vec3 == Ignition::Math::Vector4d.new(0.0125, 0.025, 0.05, 0.1), | |
219 | "Vector4 vec3 should qual [0.0125, 0.025, 0.05, 0.1]") | |
220 | end | |
221 | ||
222 | def test_multiply | |
223 | v = Ignition::Math::Vector4d.new(0.1, 0.2, 0.3, 0.4) | |
224 | ||
225 | vec3 = v * 2.0 | |
226 | assert(vec3 == Ignition::Math::Vector4d.new(0.2, 0.4, 0.6, 0.8), | |
227 | "Vector4 vec3 should equal[0.2, 0.4, 0.6, 0.8]") | |
228 | ||
229 | vec3 *= 4.0 | |
230 | assert(vec3 == Ignition::Math::Vector4d.new(0.8, 1.6, 2.4, 3.2), | |
231 | "Vector4 vec3 should equal [0.8, 1.6, 2.4, 3.2]") | |
232 | ||
233 | # Multiply by zero | |
234 | ||
235 | # Scalar left and right | |
236 | assert(v * 0 == Ignition::Math::Vector4d.Zero, | |
237 | "Vector4 v * 0 should equal Zero") | |
238 | ||
239 | # Element-wise vector multiplication | |
240 | assert(v * Ignition::Math::Vector4d.Zero == Ignition::Math::Vector4d.Zero, | |
241 | "Vector4 v * Zero should equal Zero") | |
242 | ||
243 | # Multiply by one | |
244 | ||
245 | # Scalar left and right | |
246 | assert(v * 1 == v, "Vector4 v * 1 should equal v") | |
247 | ||
248 | # Element-wise vector multiplication | |
249 | assert(v * Ignition::Math::Vector4d.One == v, | |
250 | "Vector4 v * One should equal v") | |
251 | ||
252 | # Multiply by non-trivial scalar value | |
253 | ||
254 | scalar = 2.5 | |
255 | expect = Ignition::Math::Vector4d.new(0.25, 0.5, 0.75, 1.0) | |
256 | assert(v * scalar == expect, | |
257 | "Vector4 v * scalar should equal [0.25, 0.5, 0.75, 1.0]") | |
258 | ||
259 | # Multiply by itself element-wise | |
260 | assert(v*v == Ignition::Math::Vector4d.new(0.01, 0.04, 0.09, 0.16), | |
261 | "Vector4 v * v should euqal [0.01, 0.04, 0.09, 0.16]") | |
262 | end | |
263 | ||
264 | def test_not_equal | |
265 | vec1 = Ignition::Math::Vector4d.new(0.1, 0.2, 0.3, 0.4) | |
266 | vec2 = Ignition::Math::Vector4d.new(0.2, 0.2, 0.3, 0.4) | |
267 | vec3 = Ignition::Math::Vector4d.new(0.1, 0.2, 0.3, 0.4) | |
268 | ||
269 | assert(vec1 != vec2, "Vector4 vec1 should not equal vec2") | |
270 | assert(!(vec1 != vec3), "Vector4 vec1 should equal vec3" ) | |
271 | end | |
272 | ||
273 | def test_equal | |
274 | assert(!Ignition::Math::Vector4d.Zero.Equal( | |
275 | Ignition::Math::Vector4d.One, 1e-6), | |
276 | "Vector4 Zero should not equal 1 with tolerance of 1e-6") | |
277 | assert(!Ignition::Math::Vector4d.Zero.Equal( | |
278 | Ignition::Math::Vector4d.One, 1e-3), | |
279 | "Vector4 Zero should not equal 1 with tolerance of 1e-3") | |
280 | assert(!Ignition::Math::Vector4d.Zero.Equal( | |
281 | Ignition::Math::Vector4d.One, 1e-1), | |
282 | "Vector4 Zero should not equal 1 with tolerance of 1e-1") | |
283 | ||
284 | assert(Ignition::Math::Vector4d.Zero.Equal( | |
285 | Ignition::Math::Vector4d.One, 1), | |
286 | "Vector4 Zero should equal 1 with tolerance of 1") | |
287 | assert(Ignition::Math::Vector4d.Zero.Equal( | |
288 | Ignition::Math::Vector4d.One, 1.1), | |
289 | "Vector4 Zero should equal 1 with tolerance of 1.1") | |
290 | end | |
291 | ||
292 | def test_finite | |
293 | vec1 = Ignition::Math::Vector4d.new(0.1, 0.2, 0.3, 0.4) | |
294 | ||
295 | assert(vec1.IsFinite(), "Vector4 vec1 should be be finite") | |
296 | end | |
297 | end | |
298 | ||
299 | exit Test::Unit::UI::Console::TestRunner.run(Vector4_TEST).passed? ? 0 : -1 |
309 | 309 | } |
310 | 310 | } |
311 | 311 | |
312 | ///////////////////////////////////////////////// | |
313 | TEST(GraphTestFixture, ToUndirectedGraph) | |
314 | { | |
315 | /// (6) | | |
316 | /// 0------>1 | | |
317 | /// | /|\ | | |
318 | /// | / | \(5) | | |
319 | /// | (2)/ | ┘ | | |
320 | /// | / | 2 | | |
321 | /// (1)| / (2)| / | | |
322 | /// | / | /(5) | | |
323 | /// VL VL | | |
324 | /// 3------>4 | | |
325 | /// (1) | | |
326 | DirectedGraph<int, double> directed( | |
327 | { | |
328 | // Vertices. | |
329 | {{"0", 0, 0}, {"1", 1, 1}, {"2", 2, 2}, {"3", 3, 3}, {"4", 4, 4}}, | |
330 | // Edges. | |
331 | {{{0, 1}, 2.0, 6.0}, {{0, 3}, 3.0, 1.0}, | |
332 | {{1, 2}, 4.0, 5.0}, {{1, 3}, 4.0, 2.0}, {{1, 4}, 4.0, 2.0}, | |
333 | {{2, 4}, 2.0, 5.0}, | |
334 | {{3, 4}, 2.0, 1.0}} | |
335 | }); | |
336 | ||
337 | // Convert to undirected graph. | |
338 | auto undirected = ToUndirectedGraph(directed); | |
339 | EXPECT_EQ(5u, undirected.Vertices().size()); | |
340 | EXPECT_EQ(7u, undirected.Edges().size()); | |
341 | EXPECT_EQ(directed.Vertices().size(), undirected.Vertices().size()); | |
342 | EXPECT_EQ(directed.Edges().size(), undirected.Edges().size()); | |
343 | ||
344 | // Compare vertices. | |
345 | for (auto const &dvPair : directed.Vertices()) | |
346 | { | |
347 | const VertexId dvId = dvPair.first; | |
348 | auto const &uv = undirected.VertexFromId(dvId); | |
349 | EXPECT_TRUE(uv.Valid()); | |
350 | EXPECT_TRUE(dvPair.second.get().Valid()); | |
351 | EXPECT_EQ(uv.Id(), dvId); | |
352 | EXPECT_EQ(uv.Name(), dvPair.second.get().Name()); | |
353 | EXPECT_EQ(uv.Data(), dvPair.second.get().Data()); | |
354 | } | |
355 | ||
356 | // Compare edges. | |
357 | for (auto const &dePair : directed.Edges()) | |
358 | { | |
359 | const EdgeId deId = dePair.first; | |
360 | auto const &ue = undirected.EdgeFromId(deId); | |
361 | EXPECT_TRUE(ue.Valid()); | |
362 | EXPECT_TRUE(dePair.second.get().Valid()); | |
363 | EXPECT_EQ(ue.Id(), deId); | |
364 | EXPECT_DOUBLE_EQ(ue.Data(), dePair.second.get().Data()); | |
365 | EXPECT_DOUBLE_EQ(ue.Weight(), dePair.second.get().Weight()); | |
366 | } | |
367 | ||
368 | // std::cerr << directed << std::endl; | |
369 | // std::cerr << undirected << std::endl; | |
370 | } |
0 | 0 | %include "Angle.i" |
1 | %include "GaussMarkovProcess.i" | |
2 | %include "Rand.i" | |
1 | 3 | %include "Vector2.i" |
2 | 4 | %include "Vector3.i" |
5 | %include "Vector4.i" |
19 | 19 | execute_process(COMMAND cmake -E make_directory ${CMAKE_BINARY_DIR}/test_results) |
20 | 20 | include_directories(${GTEST_INCLUDE_DIRS}) |
21 | 21 | |
22 | #============================================================================ | |
23 | # Do a fake install of ign-math in order to test the examples. | |
24 | #============================================================================ | |
25 | set(FAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/fake/install") | |
26 | ||
27 | file(MAKE_DIRECTORY ${FAKE_INSTALL_PREFIX}) | |
28 | ||
29 | include(ExternalProject) | |
30 | ExternalProject_Add( | |
31 | FAKE_INSTALL | |
32 | ||
33 | SOURCE_DIR "${CMAKE_SOURCE_DIR}" | |
34 | EXCLUDE_FROM_ALL 1 | |
35 | LOG_CONFIGURE 1 | |
36 | LOG_BUILD 1 | |
37 | LOG_INSTALL 1 | |
38 | CMAKE_ARGS | |
39 | "-DBUILD_TESTING=OFF" | |
40 | "-DCMAKE_INSTALL_PREFIX=${FAKE_INSTALL_PREFIX}" | |
41 | ) | |
42 | ||
22 | 43 | add_subdirectory(integration) |
23 | 44 | add_subdirectory(performance) |
24 | 45 | add_subdirectory(regression) |
0 | 0 | set(TEST_TYPE "INTEGRATION") |
1 | 1 | |
2 | set(tests | |
3 | ) | |
4 | ||
5 | link_directories(${PROJECT_BINARY_DIR}/test) | |
2 | ign_get_sources(tests) | |
6 | 3 | |
7 | 4 | # Test symbols having the right name on linux only |
8 | 5 | if (UNIX AND NOT APPLE) |
12 | 9 | endif() |
13 | 10 | |
14 | 11 | ign_build_tests(TYPE INTEGRATION SOURCES ${tests}) |
12 | ||
13 | if(TARGET INTEGRATION_ExamplesBuild_TEST) | |
14 | add_dependencies(INTEGRATION_ExamplesBuild_TEST FAKE_INSTALL) | |
15 | ||
16 | set(_env_vars) | |
17 | list(APPEND _env_vars "CMAKE_PREFIX_PATH=${FAKE_INSTALL_PREFIX}:$ENV{CMAKE_PREFIX_PATH}") | |
18 | set_tests_properties(INTEGRATION_ExamplesBuild_TEST PROPERTIES | |
19 | ENVIRONMENT "${_env_vars}") | |
20 | endif() |
0 | /* | |
1 | * Copyright (C) 2019 Open Source Robotics Foundation | |
2 | * | |
3 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
4 | * you may not use this file except in compliance with the License. | |
5 | * You may obtain a copy of the License at | |
6 | * | |
7 | * http://www.apache.org/licenses/LICENSE-2.0 | |
8 | * | |
9 | * Unless required by applicable law or agreed to in writing, software | |
10 | * distributed under the License is distributed on an "AS IS" BASIS, | |
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 | * See the License for the specific language governing permissions and | |
13 | * limitations under the License. | |
14 | * | |
15 | */ | |
16 | ||
17 | #include <gtest/gtest.h> | |
18 | #include <cstring> | |
19 | #include <fstream> | |
20 | #include <string> | |
21 | ||
22 | #include "test_config.h" // NOLINT(build/include) | |
23 | ||
24 | #ifdef _WIN32 | |
25 | # define IGN_PATH_MAX _MAX_PATH | |
26 | #elif defined(PATH_MAX) | |
27 | # define IGN_PATH_MAX PATH_MAX | |
28 | #elif defined(_XOPEN_PATH_MAX) | |
29 | # define IGN_PATH_MAX _XOPEN_PATH_MAX | |
30 | #else | |
31 | # define IGN_PATH_MAX _POSIX_PATH_MAX | |
32 | #endif | |
33 | ||
34 | ||
35 | // Helper functions copied from | |
36 | // https://github.com/ignitionrobotics/ign-common/raw/master/src/Filesystem_TEST.cc | |
37 | ||
38 | #ifndef _WIN32 | |
39 | #include <dirent.h> // NOLINT(build/include_order) | |
40 | #include <fcntl.h> // NOLINT(build/include_order) | |
41 | #include <limits.h> // NOLINT(build/include_order) | |
42 | #include <stdlib.h> // NOLINT(build/include_order) | |
43 | #include <sys/stat.h> // NOLINT(build/include_order) | |
44 | #include <sys/types.h> // NOLINT(build/include_order) | |
45 | #include <unistd.h> // NOLINT(build/include_order) | |
46 | ||
47 | ///////////////////////////////////////////////// | |
48 | bool createAndSwitchToTempDir(std::string &_newTempPath) | |
49 | { | |
50 | std::string tmppath; | |
51 | const char *tmp = std::getenv("TMPDIR"); | |
52 | if (tmp) | |
53 | { | |
54 | tmppath = std::string(tmp); | |
55 | } | |
56 | else | |
57 | { | |
58 | tmppath = std::string("/tmp"); | |
59 | } | |
60 | ||
61 | tmppath += "/XXXXXX"; | |
62 | ||
63 | char *dtemp = mkdtemp(const_cast<char *>(tmppath.c_str())); | |
64 | if (dtemp == nullptr) | |
65 | { | |
66 | return false; | |
67 | } | |
68 | if (chdir(dtemp) < 0) | |
69 | { | |
70 | return false; | |
71 | } | |
72 | ||
73 | // cppcheck-suppress * | |
74 | char resolved[PATH_MAX]; | |
75 | if (realpath(dtemp, resolved) == nullptr) | |
76 | { | |
77 | return false; | |
78 | } | |
79 | ||
80 | _newTempPath = std::string(resolved); | |
81 | ||
82 | return true; | |
83 | } | |
84 | ||
85 | #else | |
86 | #include <io.h> // NOLINT(build/include_order) | |
87 | #include <windows.h> // NOLINT(build/include_order) | |
88 | #include <winioctl.h> // NOLINT(build/include_order) | |
89 | #include <winnt.h> // NOLINT(build/include_order) | |
90 | #include <cstdint> | |
91 | #include "./win_dirent.h" | |
92 | ||
93 | ///////////////////////////////////////////////// | |
94 | bool createAndSwitchToTempDir(std::string &_newTempPath) | |
95 | { | |
96 | char tempPath[MAX_PATH + 1]; | |
97 | DWORD pathLen = ::GetTempPathA(MAX_PATH, tempPath); | |
98 | if (pathLen >= MAX_PATH || pathLen <= 0) | |
99 | { | |
100 | return false; | |
101 | } | |
102 | std::string pathToCreate(tempPath); | |
103 | srand(static_cast<uint32_t>(time(nullptr))); | |
104 | ||
105 | for (int count = 0; count < 50; ++count) | |
106 | { | |
107 | // Try creating a new temporary directory with a randomly generated name. | |
108 | // If the one we chose exists, keep trying another path name until we reach | |
109 | // some limit. | |
110 | std::string newDirName; | |
111 | newDirName.append(std::to_string(::GetCurrentProcessId())); | |
112 | newDirName.push_back('_'); | |
113 | // On Windows, rand_r() doesn't exist as an alternative to rand(), so the | |
114 | // cpplint warning is spurious. This program is not multi-threaded, so | |
115 | // it is safe to suppress the threadsafe_fn warning here. | |
116 | newDirName.append( | |
117 | std::to_string(rand() // NOLINT(runtime/threadsafe_fn) | |
118 | % ((int16_t)0x7fff))); | |
119 | ||
120 | pathToCreate += newDirName; | |
121 | if (::CreateDirectoryA(pathToCreate.c_str(), nullptr)) | |
122 | { | |
123 | _newTempPath = pathToCreate; | |
124 | return ::SetCurrentDirectoryA(_newTempPath.c_str()) != 0; | |
125 | } | |
126 | } | |
127 | ||
128 | return false; | |
129 | } | |
130 | ||
131 | struct handle_wrapper | |
132 | { | |
133 | HANDLE handle; | |
134 | explicit handle_wrapper(HANDLE h) | |
135 | : handle(h) {} | |
136 | ~handle_wrapper() | |
137 | { | |
138 | if (handle != INVALID_HANDLE_VALUE) | |
139 | { | |
140 | ::CloseHandle(handle); | |
141 | } | |
142 | } | |
143 | }; | |
144 | ||
145 | ////////////////////////////////////////////////// | |
146 | HANDLE create_file_handle(const std::string &_path, DWORD _dwDesiredAccess, | |
147 | DWORD _dwShareMode, | |
148 | LPSECURITY_ATTRIBUTES _lpSecurityAttributes, | |
149 | DWORD _dwCreationDisposition, | |
150 | DWORD _dwFlagsAndAttributes, | |
151 | HANDLE _hTemplateFile) | |
152 | { | |
153 | return ::CreateFileA(_path.c_str(), _dwDesiredAccess, | |
154 | _dwShareMode, _lpSecurityAttributes, | |
155 | _dwCreationDisposition, _dwFlagsAndAttributes, | |
156 | _hTemplateFile); | |
157 | } | |
158 | ||
159 | ////////////////////////////////////////////////// | |
160 | bool not_found_error(int _errval) | |
161 | { | |
162 | return _errval == ERROR_FILE_NOT_FOUND | |
163 | || _errval == ERROR_PATH_NOT_FOUND | |
164 | || _errval == ERROR_INVALID_NAME // "tools/src/:sys:stat.h", "//foo" | |
165 | || _errval == ERROR_INVALID_DRIVE // USB card reader with no card | |
166 | || _errval == ERROR_NOT_READY // CD/DVD drive with no disc inserted | |
167 | || _errval == ERROR_INVALID_PARAMETER // ":sys:stat.h" | |
168 | || _errval == ERROR_BAD_PATHNAME // "//nosuch" on Win64 | |
169 | || _errval == ERROR_BAD_NETPATH; // "//nosuch" on Win32 | |
170 | } | |
171 | ||
172 | #ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE | |
173 | #define MAXIMUM_REPARSE_DATA_BUFFER_SIZE (16 * 1024) | |
174 | #endif | |
175 | ||
176 | typedef struct _REPARSE_DATA_BUFFER { | |
177 | ULONG ReparseTag; | |
178 | USHORT ReparseDataLength; | |
179 | USHORT Reserved; | |
180 | union { | |
181 | struct { | |
182 | USHORT SubstituteNameOffset; | |
183 | USHORT SubstituteNameLength; | |
184 | USHORT PrintNameOffset; | |
185 | USHORT PrintNameLength; | |
186 | ULONG Flags; | |
187 | WCHAR PathBuffer[1]; | |
188 | /* Example of distinction between substitute and print names: | |
189 | mklink /d ldrive c:\ | |
190 | SubstituteName: c:\\??\ | |
191 | PrintName: c:\ | |
192 | */ | |
193 | } SymbolicLinkReparseBuffer; | |
194 | struct { | |
195 | USHORT SubstituteNameOffset; | |
196 | USHORT SubstituteNameLength; | |
197 | USHORT PrintNameOffset; | |
198 | USHORT PrintNameLength; | |
199 | WCHAR PathBuffer[1]; | |
200 | } MountPointReparseBuffer; | |
201 | struct { | |
202 | UCHAR DataBuffer[1]; | |
203 | } GenericReparseBuffer; | |
204 | }; | |
205 | } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; | |
206 | ||
207 | ////////////////////////////////////////////////// | |
208 | bool is_reparse_point_a_symlink(const std::string &_path) | |
209 | { | |
210 | handle_wrapper h(create_file_handle(_path, FILE_READ_EA, | |
211 | FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, | |
212 | nullptr, OPEN_EXISTING, | |
213 | FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, | |
214 | nullptr)); | |
215 | if (h.handle == INVALID_HANDLE_VALUE) | |
216 | { | |
217 | return false; | |
218 | } | |
219 | ||
220 | std::vector<wchar_t> buf(MAXIMUM_REPARSE_DATA_BUFFER_SIZE); | |
221 | ||
222 | // Query the reparse data | |
223 | DWORD dwRetLen; | |
224 | BOOL result = ::DeviceIoControl(h.handle, FSCTL_GET_REPARSE_POINT, | |
225 | nullptr, 0, buf.data(), (DWORD)buf.size(), &dwRetLen, nullptr); | |
226 | if (!result) | |
227 | { | |
228 | return false; | |
229 | } | |
230 | ||
231 | return reinterpret_cast<const REPARSE_DATA_BUFFER*>(&buf[0])->ReparseTag | |
232 | == IO_REPARSE_TAG_SYMLINK | |
233 | // Issue 9016 asked that NTFS directory junctions be recognized as | |
234 | // directories. That is equivalent to recognizing them as symlinks, and | |
235 | // then the normal symlink mechanism will recognize them as directories. | |
236 | // | |
237 | // Directory junctions are very similar to symlinks, but have some | |
238 | // performance and other advantages over symlinks. They can be created | |
239 | // from the command line with "mklink /j junction-name target-path". | |
240 | || reinterpret_cast<const REPARSE_DATA_BUFFER*>(&buf[0])->ReparseTag | |
241 | == IO_REPARSE_TAG_MOUNT_POINT; // "directory junction" or "junction" | |
242 | } | |
243 | ||
244 | ////////////////////////////////////////////////// | |
245 | bool process_status_failure() | |
246 | { | |
247 | int errval(::GetLastError()); | |
248 | ||
249 | if (not_found_error(errval)) | |
250 | { | |
251 | return false; | |
252 | } | |
253 | else if ((errval == ERROR_SHARING_VIOLATION)) | |
254 | { | |
255 | return true; // odd, but this is what boost does | |
256 | } | |
257 | return false; | |
258 | } | |
259 | ||
260 | ////////////////////////////////////////////////// | |
261 | bool internal_check_path(const std::string &_path, DWORD &attr) | |
262 | { | |
263 | attr = ::GetFileAttributesA(_path.c_str()); | |
264 | if (attr == 0xFFFFFFFF) | |
265 | { | |
266 | return process_status_failure(); | |
267 | } | |
268 | ||
269 | // reparse point handling; | |
270 | // since GetFileAttributesW does not resolve symlinks, try to open file | |
271 | // handle to discover if the file exists | |
272 | if (attr & FILE_ATTRIBUTE_REPARSE_POINT) | |
273 | { | |
274 | handle_wrapper h( | |
275 | create_file_handle( | |
276 | _path, | |
277 | 0, // dwDesiredAccess; attributes only | |
278 | FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, | |
279 | 0, // lpSecurityAttributes | |
280 | OPEN_EXISTING, | |
281 | FILE_FLAG_BACKUP_SEMANTICS, | |
282 | 0)); // hTemplateFile | |
283 | if (h.handle == INVALID_HANDLE_VALUE) | |
284 | { | |
285 | return process_status_failure(); | |
286 | } | |
287 | ||
288 | if (!is_reparse_point_a_symlink(_path)) | |
289 | { | |
290 | return true; | |
291 | } | |
292 | } | |
293 | ||
294 | return true; | |
295 | } | |
296 | #endif | |
297 | ||
298 | ////////////////////////////////////////////////// | |
299 | bool isDirectory(const std::string &_path) | |
300 | { | |
301 | #ifndef _WIN32 | |
302 | struct stat path_stat; | |
303 | ||
304 | if (::stat(_path.c_str(), &path_stat) != 0) | |
305 | { | |
306 | return false; | |
307 | } | |
308 | ||
309 | // cppcheck-suppress ConfigurationNotChecked | |
310 | return S_ISDIR(path_stat.st_mode); | |
311 | #else | |
312 | DWORD attr; | |
313 | ||
314 | if (internal_check_path(_path, attr)) | |
315 | { | |
316 | return (attr & FILE_ATTRIBUTE_DIRECTORY) != 0; | |
317 | } | |
318 | ||
319 | return false; | |
320 | #endif | |
321 | } | |
322 | ||
323 | ////////////////////////////////////////////////// | |
324 | bool isFile(const std::string &_path) | |
325 | { | |
326 | std::ifstream f(_path); | |
327 | return (!isDirectory(_path)) && f.good(); | |
328 | } | |
329 | ||
330 | ////////////////////////////////////////////////// | |
331 | void removeAll(const std::string &_path) | |
332 | { | |
333 | if (isDirectory(_path)) | |
334 | { | |
335 | DIR *dir = opendir(_path.c_str()); | |
336 | if (dir) | |
337 | { | |
338 | struct dirent *p; | |
339 | while ((p=readdir(dir))) | |
340 | { | |
341 | // Skip special files. | |
342 | if (!std::strcmp(p->d_name, ".") || !std::strcmp(p->d_name, "..")) | |
343 | continue; | |
344 | ||
345 | removeAll(_path + "/" + p->d_name); | |
346 | } | |
347 | } | |
348 | closedir(dir); | |
349 | ||
350 | // Remove the directory | |
351 | bool removed; | |
352 | #ifdef _WIN32 | |
353 | removed = RemoveDirectory(_path.c_str()); | |
354 | #else | |
355 | removed = (rmdir(_path.c_str()) == 0); | |
356 | if (!removed) | |
357 | { | |
358 | // A sym link would end up here | |
359 | removed = (std::remove(_path.c_str()) == 0); | |
360 | } | |
361 | #endif | |
362 | ASSERT_TRUE(removed); | |
363 | } | |
364 | else if (isFile(_path)) | |
365 | { | |
366 | const bool removed = (std::remove(_path.c_str()) == 0); | |
367 | ASSERT_TRUE(removed); | |
368 | } | |
369 | } | |
370 | ||
371 | ////////////////////////////////////////////////// | |
372 | TEST(ExamplesBuild, Build) | |
373 | { | |
374 | // \todo(nkoenig) Fix windows. | |
375 | #ifndef _WIN32 | |
376 | // Path to examples of the given type | |
377 | std::string examplesDir = std::string(PROJECT_SOURCE_PATH) + "/examples/"; | |
378 | ||
379 | // Create a temp build directory | |
380 | std::string tmpBuildDir; | |
381 | ASSERT_TRUE(createAndSwitchToTempDir(tmpBuildDir)); | |
382 | std::cout << "Build directory: " << tmpBuildDir<< std::endl; | |
383 | ||
384 | char cmd[1024]; | |
385 | ||
386 | // cd build && cmake source | |
387 | snprintf(cmd, sizeof(cmd), "cd %s && cmake %s && make", | |
388 | tmpBuildDir.c_str(), examplesDir.c_str()); | |
389 | ASSERT_EQ(system(cmd), 0); | |
390 | ||
391 | // Remove temp dir | |
392 | removeAll(tmpBuildDir); | |
393 | #endif | |
394 | } | |
395 | ||
396 | ////////////////////////////////////////////////// | |
397 | int main(int argc, char **argv) | |
398 | { | |
399 | ::testing::InitGoogleTest(&argc, argv); | |
400 | return RUN_ALL_TESTS(); | |
401 | } |
0 | /* | |
1 | * Dirent interface for Microsoft Visual Studio | |
2 | * Version 1.21 | |
3 | * | |
4 | * Copyright (C) 2006-2012 Toni Ronkko | |
5 | * This file is part of dirent. Dirent may be freely distributed | |
6 | * under the MIT license. For all details and documentation, see | |
7 | * https://github.com/tronkko/dirent | |
8 | */ | |
9 | #ifndef DIRENT_H | |
10 | #define DIRENT_H | |
11 | ||
12 | /* | |
13 | * Include windows.h without Windows Sockets 1.1 to prevent conflicts with | |
14 | * Windows Sockets 2.0. | |
15 | */ | |
16 | #ifndef WIN32_LEAN_AND_MEAN | |
17 | # define WIN32_LEAN_AND_MEAN | |
18 | #endif | |
19 | #include <windows.h> | |
20 | ||
21 | #include <stdio.h> | |
22 | #include <stdarg.h> | |
23 | #include <wchar.h> | |
24 | #include <string.h> | |
25 | #include <stdlib.h> | |
26 | #include <malloc.h> | |
27 | #include <sys/types.h> | |
28 | #include <sys/stat.h> | |
29 | #include <errno.h> | |
30 | ||
31 | /* Indicates that d_type field is available in dirent structure */ | |
32 | #define _DIRENT_HAVE_D_TYPE | |
33 | ||
34 | /* Indicates that d_namlen field is available in dirent structure */ | |
35 | #define _DIRENT_HAVE_D_NAMLEN | |
36 | ||
37 | /* Entries missing from MSVC 6.0 */ | |
38 | #if !defined(FILE_ATTRIBUTE_DEVICE) | |
39 | # define FILE_ATTRIBUTE_DEVICE 0x40 | |
40 | #endif | |
41 | ||
42 | /* File type and permission flags for stat(), general mask */ | |
43 | #if !defined(S_IFMT) | |
44 | # define S_IFMT _S_IFMT | |
45 | #endif | |
46 | ||
47 | /* Directory bit */ | |
48 | #if !defined(S_IFDIR) | |
49 | # define S_IFDIR _S_IFDIR | |
50 | #endif | |
51 | ||
52 | /* Character device bit */ | |
53 | #if !defined(S_IFCHR) | |
54 | # define S_IFCHR _S_IFCHR | |
55 | #endif | |
56 | ||
57 | /* Pipe bit */ | |
58 | #if !defined(S_IFFIFO) | |
59 | # define S_IFFIFO _S_IFFIFO | |
60 | #endif | |
61 | ||
62 | /* Regular file bit */ | |
63 | #if !defined(S_IFREG) | |
64 | # define S_IFREG _S_IFREG | |
65 | #endif | |
66 | ||
67 | /* Read permission */ | |
68 | #if !defined(S_IREAD) | |
69 | # define S_IREAD _S_IREAD | |
70 | #endif | |
71 | ||
72 | /* Write permission */ | |
73 | #if !defined(S_IWRITE) | |
74 | # define S_IWRITE _S_IWRITE | |
75 | #endif | |
76 | ||
77 | /* Execute permission */ | |
78 | #if !defined(S_IEXEC) | |
79 | # define S_IEXEC _S_IEXEC | |
80 | #endif | |
81 | ||
82 | /* Pipe */ | |
83 | #if !defined(S_IFIFO) | |
84 | # define S_IFIFO _S_IFIFO | |
85 | #endif | |
86 | ||
87 | /* Block device */ | |
88 | #if !defined(S_IFBLK) | |
89 | # define S_IFBLK 0 | |
90 | #endif | |
91 | ||
92 | /* Link */ | |
93 | #if !defined(S_IFLNK) | |
94 | # define S_IFLNK 0 | |
95 | #endif | |
96 | ||
97 | /* Socket */ | |
98 | #if !defined(S_IFSOCK) | |
99 | # define S_IFSOCK 0 | |
100 | #endif | |
101 | ||
102 | /* Read user permission */ | |
103 | #if !defined(S_IRUSR) | |
104 | # define S_IRUSR S_IREAD | |
105 | #endif | |
106 | ||
107 | /* Write user permission */ | |
108 | #if !defined(S_IWUSR) | |
109 | # define S_IWUSR S_IWRITE | |
110 | #endif | |
111 | ||
112 | /* Execute user permission */ | |
113 | #if !defined(S_IXUSR) | |
114 | # define S_IXUSR 0 | |
115 | #endif | |
116 | ||
117 | /* Read group permission */ | |
118 | #if !defined(S_IRGRP) | |
119 | # define S_IRGRP 0 | |
120 | #endif | |
121 | ||
122 | /* Write group permission */ | |
123 | #if !defined(S_IWGRP) | |
124 | # define S_IWGRP 0 | |
125 | #endif | |
126 | ||
127 | /* Execute group permission */ | |
128 | #if !defined(S_IXGRP) | |
129 | # define S_IXGRP 0 | |
130 | #endif | |
131 | ||
132 | /* Read others permission */ | |
133 | #if !defined(S_IROTH) | |
134 | # define S_IROTH 0 | |
135 | #endif | |
136 | ||
137 | /* Write others permission */ | |
138 | #if !defined(S_IWOTH) | |
139 | # define S_IWOTH 0 | |
140 | #endif | |
141 | ||
142 | /* Execute others permission */ | |
143 | #if !defined(S_IXOTH) | |
144 | # define S_IXOTH 0 | |
145 | #endif | |
146 | ||
147 | /* Maximum length of file name */ | |
148 | #if !defined(PATH_MAX) | |
149 | # define PATH_MAX MAX_PATH | |
150 | #endif | |
151 | #if !defined(FILENAME_MAX) | |
152 | # define FILENAME_MAX MAX_PATH | |
153 | #endif | |
154 | #if !defined(NAME_MAX) | |
155 | # define NAME_MAX FILENAME_MAX | |
156 | #endif | |
157 | ||
158 | /* File type flags for d_type */ | |
159 | #define DT_UNKNOWN 0 | |
160 | #define DT_REG S_IFREG | |
161 | #define DT_DIR S_IFDIR | |
162 | #define DT_FIFO S_IFIFO | |
163 | #define DT_SOCK S_IFSOCK | |
164 | #define DT_CHR S_IFCHR | |
165 | #define DT_BLK S_IFBLK | |
166 | #define DT_LNK S_IFLNK | |
167 | ||
168 | /* Macros for converting between st_mode and d_type */ | |
169 | #define IFTODT(mode) ((mode) & S_IFMT) | |
170 | #define DTTOIF(type) (type) | |
171 | ||
172 | /* | |
173 | * File type macros. Note that block devices, sockets and links cannot be | |
174 | * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are | |
175 | * only defined for compatibility. These macros should always return false | |
176 | * on Windows. | |
177 | */ | |
178 | #if !defined(S_ISFIFO) | |
179 | # define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO) | |
180 | #endif | |
181 | #if !defined(S_ISDIR) | |
182 | # define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) | |
183 | #endif | |
184 | #if !defined(S_ISREG) | |
185 | # define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) | |
186 | #endif | |
187 | #if !defined(S_ISLNK) | |
188 | # define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) | |
189 | #endif | |
190 | #if !defined(S_ISSOCK) | |
191 | # define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) | |
192 | #endif | |
193 | #if !defined(S_ISCHR) | |
194 | # define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) | |
195 | #endif | |
196 | #if !defined(S_ISBLK) | |
197 | # define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) | |
198 | #endif | |
199 | ||
200 | /* Return the exact length of d_namlen without zero terminator */ | |
201 | #define _D_EXACT_NAMLEN(p) ((p)->d_namlen) | |
202 | ||
203 | /* Return number of bytes needed to store d_namlen */ | |
204 | #define _D_ALLOC_NAMLEN(p) (PATH_MAX) | |
205 | ||
206 | ||
207 | #ifdef __cplusplus | |
208 | extern "C" { | |
209 | #endif | |
210 | ||
211 | ||
212 | /* Wide-character version */ | |
213 | struct _wdirent { | |
214 | /* Always zero */ | |
215 | long d_ino; | |
216 | ||
217 | /* Structure size */ | |
218 | unsigned short d_reclen; | |
219 | ||
220 | /* Length of name without \0 */ | |
221 | size_t d_namlen; | |
222 | ||
223 | /* File type */ | |
224 | int d_type; | |
225 | ||
226 | /* File name */ | |
227 | // cppcheck-suppress * | |
228 | wchar_t d_name[PATH_MAX]; | |
229 | }; | |
230 | typedef struct _wdirent _wdirent; | |
231 | ||
232 | struct _WDIR { | |
233 | /* Current directory entry */ | |
234 | struct _wdirent ent; | |
235 | ||
236 | /* Private file data */ | |
237 | WIN32_FIND_DATAW data; | |
238 | ||
239 | /* True if data is valid */ | |
240 | int cached; | |
241 | ||
242 | /* Win32 search handle */ | |
243 | HANDLE handle; | |
244 | ||
245 | /* Initial directory name */ | |
246 | wchar_t *patt; | |
247 | }; | |
248 | typedef struct _WDIR _WDIR; | |
249 | ||
250 | static _WDIR *_wopendir (const wchar_t *dirname); | |
251 | static struct _wdirent *_wreaddir (_WDIR *dirp); | |
252 | static int _wclosedir (_WDIR *dirp); | |
253 | static void _wrewinddir (_WDIR* dirp); | |
254 | ||
255 | ||
256 | /* For compatibility with Symbian */ | |
257 | #define wdirent _wdirent | |
258 | #define WDIR _WDIR | |
259 | #define wopendir _wopendir | |
260 | #define wreaddir _wreaddir | |
261 | #define wclosedir _wclosedir | |
262 | #define wrewinddir _wrewinddir | |
263 | ||
264 | ||
265 | /* Multi-byte character versions */ | |
266 | struct dirent { | |
267 | /* Always zero */ | |
268 | long d_ino; | |
269 | ||
270 | /* Structure size */ | |
271 | unsigned short d_reclen; | |
272 | ||
273 | /* Length of name without \0 */ | |
274 | size_t d_namlen; | |
275 | ||
276 | /* File type */ | |
277 | int d_type; | |
278 | ||
279 | /* File name */ | |
280 | // cppcheck-suppress * | |
281 | char d_name[PATH_MAX]; | |
282 | }; | |
283 | typedef struct dirent dirent; | |
284 | ||
285 | struct DIR { | |
286 | struct dirent ent; | |
287 | struct _WDIR *wdirp; | |
288 | }; | |
289 | typedef struct DIR DIR; | |
290 | ||
291 | static DIR *opendir (const char *dirname); | |
292 | static struct dirent *readdir (DIR *dirp); | |
293 | static int closedir (DIR *dirp); | |
294 | static void rewinddir (DIR* dirp); | |
295 | ||
296 | ||
297 | /* Internal utility functions */ | |
298 | static WIN32_FIND_DATAW *dirent_first (_WDIR *dirp); | |
299 | static WIN32_FIND_DATAW *dirent_next (_WDIR *dirp); | |
300 | ||
301 | static int dirent_mbstowcs_s( | |
302 | size_t *pReturnValue, | |
303 | wchar_t *wcstr, | |
304 | size_t sizeInWords, | |
305 | const char *mbstr, | |
306 | size_t count); | |
307 | ||
308 | static int dirent_wcstombs_s( | |
309 | size_t *pReturnValue, | |
310 | char *mbstr, | |
311 | size_t sizeInBytes, | |
312 | const wchar_t *wcstr, | |
313 | size_t count); | |
314 | ||
315 | static void dirent_set_errno (int error); | |
316 | ||
317 | /* | |
318 | * Open directory stream DIRNAME for read and return a pointer to the | |
319 | * internal working area that is used to retrieve individual directory | |
320 | * entries. | |
321 | */ | |
322 | static _WDIR* | |
323 | _wopendir( | |
324 | const wchar_t *dirname) | |
325 | { | |
326 | _WDIR *dirp = NULL; | |
327 | int error; | |
328 | ||
329 | /* Must have directory name */ | |
330 | if (dirname == NULL || dirname[0] == '\0') { | |
331 | dirent_set_errno (ENOENT); | |
332 | return NULL; | |
333 | } | |
334 | ||
335 | /* Allocate new _WDIR structure */ | |
336 | dirp = (_WDIR*) malloc (sizeof (struct _WDIR)); | |
337 | if (dirp != NULL) { | |
338 | DWORD n; | |
339 | ||
340 | /* Reset _WDIR structure */ | |
341 | dirp->handle = INVALID_HANDLE_VALUE; | |
342 | dirp->patt = NULL; | |
343 | dirp->cached = 0; | |
344 | ||
345 | /* Compute the length of full path plus zero terminator | |
346 | * | |
347 | * Note that on WinRT there's no way to convert relative paths | |
348 | * into absolute paths, so just assume its an absolute path. | |
349 | */ | |
350 | # if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) | |
351 | n = wcslen(dirname); | |
352 | # else | |
353 | n = GetFullPathNameW (dirname, 0, NULL, NULL); | |
354 | # endif | |
355 | ||
356 | /* Allocate room for absolute directory name and search pattern */ | |
357 | dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16); | |
358 | if (dirp->patt) { | |
359 | ||
360 | /* | |
361 | * Convert relative directory name to an absolute one. This | |
362 | * allows rewinddir() to function correctly even when current | |
363 | * working directory is changed between opendir() and rewinddir(). | |
364 | * | |
365 | * Note that on WinRT there's no way to convert relative paths | |
366 | * into absolute paths, so just assume its an absolute path. | |
367 | */ | |
368 | # if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) | |
369 | wcsncpy_s(dirp->patt, n+1, dirname, n); | |
370 | # else | |
371 | n = GetFullPathNameW (dirname, n, dirp->patt, NULL); | |
372 | # endif | |
373 | if (n > 0) { | |
374 | wchar_t *p; | |
375 | ||
376 | /* Append search pattern \* to the directory name */ | |
377 | p = dirp->patt + n; | |
378 | if (dirp->patt < p) { | |
379 | switch (p[-1]) { | |
380 | case '\\': | |
381 | case '/': | |
382 | case ':': | |
383 | /* Directory ends in path separator, e.g. c:\temp\ */ | |
384 | /*NOP*/; | |
385 | break; | |
386 | ||
387 | default: | |
388 | /* Directory name doesn't end in path separator */ | |
389 | *p++ = '\\'; | |
390 | } | |
391 | } | |
392 | *p++ = '*'; | |
393 | *p = '\0'; | |
394 | ||
395 | /* Open directory stream and retrieve the first entry */ | |
396 | if (dirent_first (dirp)) { | |
397 | /* Directory stream opened successfully */ | |
398 | error = 0; | |
399 | } else { | |
400 | /* Cannot retrieve first entry */ | |
401 | error = 1; | |
402 | dirent_set_errno (ENOENT); | |
403 | } | |
404 | ||
405 | } else { | |
406 | /* Cannot retrieve full path name */ | |
407 | dirent_set_errno (ENOENT); | |
408 | error = 1; | |
409 | } | |
410 | ||
411 | } else { | |
412 | /* Cannot allocate memory for search pattern */ | |
413 | error = 1; | |
414 | } | |
415 | ||
416 | } else { | |
417 | /* Cannot allocate _WDIR structure */ | |
418 | error = 1; | |
419 | } | |
420 | ||
421 | /* Clean up in case of error */ | |
422 | if (error && dirp) { | |
423 | _wclosedir (dirp); | |
424 | dirp = NULL; | |
425 | } | |
426 | ||
427 | return dirp; | |
428 | } | |
429 | ||
430 | /* | |
431 | * Read next directory entry. The directory entry is returned in dirent | |
432 | * structure in the d_name field. Individual directory entries returned by | |
433 | * this function include regular files, sub-directories, pseudo-directories | |
434 | * "." and ".." as well as volume labels, hidden files and system files. | |
435 | */ | |
436 | static struct _wdirent* | |
437 | _wreaddir( | |
438 | _WDIR *dirp) | |
439 | { | |
440 | WIN32_FIND_DATAW *datap; | |
441 | struct _wdirent *entp; | |
442 | ||
443 | /* Read next directory entry */ | |
444 | datap = dirent_next (dirp); | |
445 | if (datap) { | |
446 | size_t n; | |
447 | DWORD attr; | |
448 | ||
449 | /* Pointer to directory entry to return */ | |
450 | entp = &dirp->ent; | |
451 | ||
452 | /* | |
453 | * Copy file name as wide-character string. If the file name is too | |
454 | * long to fit in to the destination buffer, then truncate file name | |
455 | * to PATH_MAX characters and zero-terminate the buffer. | |
456 | */ | |
457 | n = 0; | |
458 | // cppcheck-suppress * | |
459 | while (n + 1 < PATH_MAX && datap->cFileName[n] != 0) { | |
460 | entp->d_name[n] = datap->cFileName[n]; | |
461 | n++; | |
462 | } | |
463 | dirp->ent.d_name[n] = 0; | |
464 | ||
465 | /* Length of file name excluding zero terminator */ | |
466 | entp->d_namlen = n; | |
467 | ||
468 | /* File type */ | |
469 | attr = datap->dwFileAttributes; | |
470 | // cppcheck-suppress * | |
471 | if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { | |
472 | // cppcheck-suppress * | |
473 | entp->d_type = DT_CHR; | |
474 | } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { | |
475 | // cppcheck-suppress * | |
476 | entp->d_type = DT_DIR; | |
477 | } else { | |
478 | // cppcheck-suppress * | |
479 | entp->d_type = DT_REG; | |
480 | } | |
481 | ||
482 | /* Reset dummy fields */ | |
483 | entp->d_ino = 0; | |
484 | entp->d_reclen = sizeof (struct _wdirent); | |
485 | ||
486 | } else { | |
487 | ||
488 | /* Last directory entry read */ | |
489 | entp = NULL; | |
490 | ||
491 | } | |
492 | ||
493 | return entp; | |
494 | } | |
495 | ||
496 | /* | |
497 | * Close directory stream opened by opendir() function. This invalidates the | |
498 | * DIR structure as well as any directory entry read previously by | |
499 | * _wreaddir(). | |
500 | */ | |
501 | static int | |
502 | _wclosedir( | |
503 | _WDIR *dirp) | |
504 | { | |
505 | int ok; | |
506 | if (dirp) { | |
507 | ||
508 | /* Release search handle */ | |
509 | if (dirp->handle != INVALID_HANDLE_VALUE) { | |
510 | FindClose (dirp->handle); | |
511 | dirp->handle = INVALID_HANDLE_VALUE; | |
512 | } | |
513 | ||
514 | /* Release search pattern */ | |
515 | if (dirp->patt) { | |
516 | free (dirp->patt); | |
517 | dirp->patt = NULL; | |
518 | } | |
519 | ||
520 | /* Release directory structure */ | |
521 | free (dirp); | |
522 | ok = /*success*/0; | |
523 | ||
524 | } else { | |
525 | /* Invalid directory stream */ | |
526 | dirent_set_errno (EBADF); | |
527 | ok = /*failure*/-1; | |
528 | } | |
529 | return ok; | |
530 | } | |
531 | ||
532 | /* | |
533 | * Rewind directory stream such that _wreaddir() returns the very first | |
534 | * file name again. | |
535 | */ | |
536 | static void | |
537 | _wrewinddir( | |
538 | _WDIR* dirp) | |
539 | { | |
540 | if (dirp) { | |
541 | /* Release existing search handle */ | |
542 | if (dirp->handle != INVALID_HANDLE_VALUE) { | |
543 | FindClose (dirp->handle); | |
544 | } | |
545 | ||
546 | /* Open new search handle */ | |
547 | dirent_first (dirp); | |
548 | } | |
549 | } | |
550 | ||
551 | /* Get first directory entry (internal) */ | |
552 | static WIN32_FIND_DATAW* | |
553 | dirent_first( | |
554 | _WDIR *dirp) | |
555 | { | |
556 | WIN32_FIND_DATAW *datap; | |
557 | ||
558 | /* Open directory and retrieve the first entry */ | |
559 | dirp->handle = FindFirstFileExW( | |
560 | dirp->patt, FindExInfoStandard, &dirp->data, | |
561 | FindExSearchNameMatch, NULL, 0); | |
562 | if (dirp->handle != INVALID_HANDLE_VALUE) { | |
563 | ||
564 | /* a directory entry is now waiting in memory */ | |
565 | datap = &dirp->data; | |
566 | dirp->cached = 1; | |
567 | ||
568 | } else { | |
569 | ||
570 | /* Failed to re-open directory: no directory entry in memory */ | |
571 | dirp->cached = 0; | |
572 | datap = NULL; | |
573 | ||
574 | } | |
575 | return datap; | |
576 | } | |
577 | ||
578 | /* Get next directory entry (internal) */ | |
579 | static WIN32_FIND_DATAW* | |
580 | dirent_next( | |
581 | _WDIR *dirp) | |
582 | { | |
583 | WIN32_FIND_DATAW *p; | |
584 | ||
585 | /* Get next directory entry */ | |
586 | if (dirp->cached != 0) { | |
587 | ||
588 | /* A valid directory entry already in memory */ | |
589 | p = &dirp->data; | |
590 | dirp->cached = 0; | |
591 | ||
592 | } else if (dirp->handle != INVALID_HANDLE_VALUE) { | |
593 | ||
594 | /* Get the next directory entry from stream */ | |
595 | if (FindNextFileW (dirp->handle, &dirp->data) != FALSE) { | |
596 | /* Got a file */ | |
597 | p = &dirp->data; | |
598 | } else { | |
599 | /* The very last entry has been processed or an error occured */ | |
600 | FindClose (dirp->handle); | |
601 | dirp->handle = INVALID_HANDLE_VALUE; | |
602 | p = NULL; | |
603 | } | |
604 | ||
605 | } else { | |
606 | ||
607 | /* End of directory stream reached */ | |
608 | p = NULL; | |
609 | ||
610 | } | |
611 | ||
612 | return p; | |
613 | } | |
614 | ||
615 | /* | |
616 | * Open directory stream using plain old C-string. | |
617 | */ | |
618 | static DIR* | |
619 | opendir( | |
620 | const char *dirname) | |
621 | { | |
622 | struct DIR *dirp; | |
623 | int error; | |
624 | ||
625 | /* Must have directory name */ | |
626 | if (dirname == NULL || dirname[0] == '\0') { | |
627 | dirent_set_errno (ENOENT); | |
628 | return NULL; | |
629 | } | |
630 | ||
631 | /* Allocate memory for DIR structure */ | |
632 | dirp = (DIR*) malloc (sizeof (struct DIR)); | |
633 | if (dirp) { | |
634 | // cppcheck-suppress * | |
635 | wchar_t wname[PATH_MAX]; | |
636 | size_t n; | |
637 | ||
638 | /* Convert directory name to wide-character string */ | |
639 | // cppcheck-suppress * | |
640 | error = dirent_mbstowcs_s (&n, wname, PATH_MAX, dirname, PATH_MAX); | |
641 | if (!error) { | |
642 | ||
643 | /* Open directory stream using wide-character name */ | |
644 | dirp->wdirp = _wopendir (wname); | |
645 | if (dirp->wdirp) { | |
646 | /* Directory stream opened */ | |
647 | error = 0; | |
648 | } else { | |
649 | /* Failed to open directory stream */ | |
650 | error = 1; | |
651 | } | |
652 | ||
653 | } else { | |
654 | /* | |
655 | * Cannot convert file name to wide-character string. This | |
656 | * occurs if the string contains invalid multi-byte sequences or | |
657 | * the output buffer is too small to contain the resulting | |
658 | * string. | |
659 | */ | |
660 | error = 1; | |
661 | } | |
662 | ||
663 | } else { | |
664 | /* Cannot allocate DIR structure */ | |
665 | error = 1; | |
666 | } | |
667 | ||
668 | /* Clean up in case of error */ | |
669 | if (error && dirp) { | |
670 | free (dirp); | |
671 | dirp = NULL; | |
672 | } | |
673 | ||
674 | return dirp; | |
675 | } | |
676 | ||
677 | /* | |
678 | * Read next directory entry. | |
679 | * | |
680 | * When working with text consoles, please note that file names returned by | |
681 | * readdir() are represented in the default ANSI code page while any output to | |
682 | * console is typically formatted on another code page. Thus, non-ASCII | |
683 | * characters in file names will not usually display correctly on console. The | |
684 | * problem can be fixed in two ways: (1) change the character set of console | |
685 | * to 1252 using chcp utility and use Lucida Console font, or (2) use | |
686 | * _cprintf function when writing to console. The _cprinf() will re-encode | |
687 | * ANSI strings to the console code page so many non-ASCII characters will | |
688 | * display correcly. | |
689 | */ | |
690 | static struct dirent* | |
691 | readdir( | |
692 | DIR *dirp) | |
693 | { | |
694 | WIN32_FIND_DATAW *datap; | |
695 | struct dirent *entp; | |
696 | ||
697 | /* Read next directory entry */ | |
698 | datap = dirent_next (dirp->wdirp); | |
699 | if (datap) { | |
700 | size_t n; | |
701 | int error; | |
702 | ||
703 | /* Attempt to convert file name to multi-byte string */ | |
704 | error = dirent_wcstombs_s( | |
705 | // cppcheck-suppress * | |
706 | &n, dirp->ent.d_name, PATH_MAX, datap->cFileName, PATH_MAX); | |
707 | ||
708 | /* | |
709 | * If the file name cannot be represented by a multi-byte string, | |
710 | * then attempt to use old 8+3 file name. This allows traditional | |
711 | * Unix-code to access some file names despite of unicode | |
712 | * characters, although file names may seem unfamiliar to the user. | |
713 | * | |
714 | * Be ware that the code below cannot come up with a short file | |
715 | * name unless the file system provides one. At least | |
716 | * VirtualBox shared folders fail to do this. | |
717 | */ | |
718 | if (error && datap->cAlternateFileName[0] != '\0') { | |
719 | error = dirent_wcstombs_s( | |
720 | // cppcheck-suppress * | |
721 | &n, dirp->ent.d_name, PATH_MAX, | |
722 | // cppcheck-suppress * | |
723 | datap->cAlternateFileName, PATH_MAX); | |
724 | } | |
725 | ||
726 | if (!error) { | |
727 | DWORD attr; | |
728 | ||
729 | /* Initialize directory entry for return */ | |
730 | entp = &dirp->ent; | |
731 | ||
732 | /* Length of file name excluding zero terminator */ | |
733 | entp->d_namlen = n - 1; | |
734 | ||
735 | /* File attributes */ | |
736 | attr = datap->dwFileAttributes; | |
737 | // cppcheck-suppress * | |
738 | if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { | |
739 | // cppcheck-suppress * | |
740 | entp->d_type = DT_CHR; | |
741 | } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { | |
742 | // cppcheck-suppress * | |
743 | entp->d_type = DT_DIR; | |
744 | } else { | |
745 | // cppcheck-suppress * | |
746 | entp->d_type = DT_REG; | |
747 | } | |
748 | ||
749 | /* Reset dummy fields */ | |
750 | entp->d_ino = 0; | |
751 | entp->d_reclen = sizeof (struct dirent); | |
752 | ||
753 | } else { | |
754 | /* | |
755 | * Cannot convert file name to multi-byte string so construct | |
756 | * an errornous directory entry and return that. Note that | |
757 | * we cannot return NULL as that would stop the processing | |
758 | * of directory entries completely. | |
759 | */ | |
760 | entp = &dirp->ent; | |
761 | entp->d_name[0] = '?'; | |
762 | entp->d_name[1] = '\0'; | |
763 | entp->d_namlen = 1; | |
764 | entp->d_type = DT_UNKNOWN; | |
765 | entp->d_ino = 0; | |
766 | entp->d_reclen = 0; | |
767 | } | |
768 | ||
769 | } else { | |
770 | /* No more directory entries */ | |
771 | entp = NULL; | |
772 | } | |
773 | ||
774 | return entp; | |
775 | } | |
776 | ||
777 | /* | |
778 | * Close directory stream. | |
779 | */ | |
780 | static int | |
781 | closedir( | |
782 | DIR *dirp) | |
783 | { | |
784 | int ok; | |
785 | if (dirp) { | |
786 | ||
787 | /* Close wide-character directory stream */ | |
788 | ok = _wclosedir (dirp->wdirp); | |
789 | dirp->wdirp = NULL; | |
790 | ||
791 | /* Release multi-byte character version */ | |
792 | free (dirp); | |
793 | ||
794 | } else { | |
795 | ||
796 | /* Invalid directory stream */ | |
797 | dirent_set_errno (EBADF); | |
798 | ok = /*failure*/-1; | |
799 | ||
800 | } | |
801 | return ok; | |
802 | } | |
803 | ||
804 | /* | |
805 | * Rewind directory stream to beginning. | |
806 | */ | |
807 | static void | |
808 | rewinddir( | |
809 | DIR* dirp) | |
810 | { | |
811 | /* Rewind wide-character string directory stream */ | |
812 | _wrewinddir (dirp->wdirp); | |
813 | } | |
814 | ||
815 | /* Convert multi-byte string to wide character string */ | |
816 | static int | |
817 | dirent_mbstowcs_s( | |
818 | size_t *pReturnValue, | |
819 | wchar_t *wcstr, | |
820 | size_t sizeInWords, | |
821 | const char *mbstr, | |
822 | size_t count) | |
823 | { | |
824 | int error; | |
825 | ||
826 | #if defined(_MSC_VER) && _MSC_VER >= 1400 | |
827 | ||
828 | /* Microsoft Visual Studio 2005 or later */ | |
829 | error = mbstowcs_s (pReturnValue, wcstr, sizeInWords, mbstr, count); | |
830 | ||
831 | #else | |
832 | ||
833 | /* Older Visual Studio or non-Microsoft compiler */ | |
834 | size_t n; | |
835 | ||
836 | /* Convert to wide-character string (or count characters) */ | |
837 | n = mbstowcs (wcstr, mbstr, sizeInWords); | |
838 | if (!wcstr || n < count) { | |
839 | ||
840 | /* Zero-terminate output buffer */ | |
841 | if (wcstr && sizeInWords) { | |
842 | if (n >= sizeInWords) { | |
843 | n = sizeInWords - 1; | |
844 | } | |
845 | wcstr[n] = 0; | |
846 | } | |
847 | ||
848 | /* Length of resuting multi-byte string WITH zero terminator */ | |
849 | if (pReturnValue) { | |
850 | *pReturnValue = n + 1; | |
851 | } | |
852 | ||
853 | /* Success */ | |
854 | error = 0; | |
855 | ||
856 | } else { | |
857 | ||
858 | /* Could not convert string */ | |
859 | error = 1; | |
860 | ||
861 | } | |
862 | ||
863 | #endif | |
864 | ||
865 | return error; | |
866 | } | |
867 | ||
868 | /* Convert wide-character string to multi-byte string */ | |
869 | static int | |
870 | dirent_wcstombs_s( | |
871 | size_t *pReturnValue, | |
872 | char *mbstr, | |
873 | size_t sizeInBytes, /* max size of mbstr */ | |
874 | const wchar_t *wcstr, | |
875 | size_t count) | |
876 | { | |
877 | int error; | |
878 | ||
879 | #if defined(_MSC_VER) && _MSC_VER >= 1400 | |
880 | ||
881 | /* Microsoft Visual Studio 2005 or later */ | |
882 | error = wcstombs_s (pReturnValue, mbstr, sizeInBytes, wcstr, count); | |
883 | ||
884 | #else | |
885 | ||
886 | /* Older Visual Studio or non-Microsoft compiler */ | |
887 | size_t n; | |
888 | ||
889 | /* Convert to multi-byte string (or count the number of bytes needed) */ | |
890 | n = wcstombs (mbstr, wcstr, sizeInBytes); | |
891 | if (!mbstr || n < count) { | |
892 | ||
893 | /* Zero-terminate output buffer */ | |
894 | if (mbstr && sizeInBytes) { | |
895 | if (n >= sizeInBytes) { | |
896 | n = sizeInBytes - 1; | |
897 | } | |
898 | mbstr[n] = '\0'; | |
899 | } | |
900 | ||
901 | /* Length of resulting multi-bytes string WITH zero-terminator */ | |
902 | if (pReturnValue) { | |
903 | *pReturnValue = n + 1; | |
904 | } | |
905 | ||
906 | /* Success */ | |
907 | error = 0; | |
908 | ||
909 | } else { | |
910 | ||
911 | /* Cannot convert string */ | |
912 | error = 1; | |
913 | ||
914 | } | |
915 | ||
916 | #endif | |
917 | ||
918 | return error; | |
919 | } | |
920 | ||
921 | /* Set errno variable */ | |
922 | static void | |
923 | dirent_set_errno( | |
924 | int error) | |
925 | { | |
926 | #if defined(_MSC_VER) && _MSC_VER >= 1400 | |
927 | ||
928 | /* Microsoft Visual Studio 2005 and later */ | |
929 | _set_errno (error); | |
930 | ||
931 | #else | |
932 | ||
933 | /* Non-Microsoft compiler or older Microsoft compiler */ | |
934 | errno = error; | |
935 | ||
936 | #endif | |
937 | } | |
938 | ||
939 | ||
940 | #ifdef __cplusplus | |
941 | } | |
942 | #endif | |
943 | #endif /*DIRENT_H*/ | |
944 |
52 | 52 | CPPCHECK_FILES=`find $CHECK_DIRS -name "*.cc" -o -name "*.hh"` |
53 | 53 | fi |
54 | 54 | CPPLINT_FILES=`\ |
55 | find $CHECK_DIRS -name "*.cc" -o -name "*.hh" -o -name "*.c" -o -name "*.h"` | |
55 | find $CHECK_DIRS -name "*.cc" -o -name "*.hh"` | |
56 | 56 | fi |
57 | 57 | |
58 | 58 | SUPPRESS=/tmp/cpp_check.suppress |
67 | 67 | touch $SUPPRESS |
68 | 68 | |
69 | 69 | #cppcheck |
70 | CPPCHECK_BASE="cppcheck -q --suppressions-list=$SUPPRESS --inline-suppr" | |
70 | CPPCHECK_BASE="cppcheck --force -q --suppressions-list=$SUPPRESS --inline-suppr" | |
71 | 71 | if [ $CPPCHECK_LT_157 -eq 0 ]; then |
72 | 72 | # use --language argument if 1.57 or greater (issue #907) |
73 | 73 | CPPCHECK_BASE="$CPPCHECK_BASE --language=c++" |
302 | 302 | 'random', |
303 | 303 | 'ratio', |
304 | 304 | 'regex', |
305 | 'scoped_allocator', | |
305 | 306 | 'set', |
306 | 307 | 'sstream', |
307 | 308 | 'stack', |
320 | 321 | 'utility', |
321 | 322 | 'valarray', |
322 | 323 | 'vector', |
324 | # 17.6.1.2 C++14 headers | |
325 | 'shared_mutex', | |
326 | # 17.6.1.2 C++17 headers | |
327 | 'any', | |
328 | 'charconv', | |
329 | 'codecvt', | |
330 | 'execution', | |
331 | 'filesystem', | |
332 | 'memory_resource', | |
333 | 'optional', | |
334 | 'string_view', | |
335 | 'variant', | |
323 | 336 | # 17.6.1.2 C++ headers for C library facilities |
324 | 337 | 'cassert', |
325 | 338 | 'ccomplex', |
1 | 1 | |
2 | 2 | Next Tutorial: \ref cppgetstarted |
3 | 3 | |
4 | ## Overview | |
4 | # Overview | |
5 | 5 | |
6 | 6 | This tutorial describes how to install Ignition Math on Linux, Mac OS X and |
7 | 7 | Windows via either a binary distribution or from source. |
8 | 8 | |
9 | ## Ubuntu Linux | |
9 | [Install](#install) | |
10 | ||
11 | * [Binary Install](#binary-install) | |
12 | ||
13 | * [Source Install](#source-install) | |
14 | ||
15 | * [Prerequisites](#prerequisites) | |
16 | ||
17 | * [Building from Source](#building-from-source) | |
18 | ||
19 | # Install | |
20 | ||
21 | We recommend following the [Binary Install](#binary-install) instructions to get up and running as quickly and painlessly as possible. | |
22 | ||
23 | The [Source Install](#source-install) instructions should be used if you need the very latest software improvements, you need to modify the code, or you plan to make a contribution. | |
24 | ||
25 | ## Binary Install | |
26 | ||
27 | ### Ubuntu Linux | |
10 | 28 | |
11 | 29 | Setup your computer to accept software from |
12 | 30 | *packages.osrfoundation.org*: |
24 | 42 | Install Ignition Math: |
25 | 43 | |
26 | 44 | ``` |
27 | sudo apt-get update | |
28 | sudo apt-get install libignition-math6-dev | |
45 | sudo apt install libignition-math<#>-dev | |
29 | 46 | ``` |
47 | ||
48 | Be sure to replace `<#>` with a number value, such as 1 or 2, depending on | |
49 | which version you need. | |
50 | ||
51 | ## Source Install | |
52 | ||
53 | Source installation can be performed in UNIX systems by first installing the | |
54 | necessary prerequisites followed by building from source. | |
55 | ||
56 | ### Prerequisites | |
57 | ||
58 | The optional Eigen component of Ignition Math requires: | |
59 | ||
60 | * [Eigen](http://eigen.tuxfamily.org/index.php?title=Main_Page). Refer to the [Eigen Documentation](http://eigen.tuxfamily.org/index.php?title=Main_Page#Documentation) for installation instructions. On Ubuntu systems, `apt-get` can be used to install Eigen: | |
61 | ||
62 | ``` | |
63 | sudo apt-get install libeigen3-dev | |
64 | ``` | |
65 | ||
66 | The optional Ruby tests of Ignition Math require: | |
67 | ||
68 | * [Ruby](https://www.ruby-lang.org/). Refer to the [Ruby Documentation](https://www.ruby-lang.org/downloads/) for installation instructions. On Ubuntu systems `apt-get` can be used to install Ubuntu Package `ruby-dev`: | |
69 | ||
70 | ``` | |
71 | sudo apt-get install ruby-dev | |
72 | ``` | |
73 | ||
74 | * [Swig](http://www.swig.org/). Refer to the [Swig Documentation](http://www.swig.org/download.html) for installation instructions. On Ubuntu systems `apt-get` can be used to install Swig: | |
75 | ||
76 | ``` | |
77 | sudo apt-get install swig | |
78 | ``` | |
79 | ||
80 | ### Building from source | |
81 | ||
82 | 1. Clone the repository | |
83 | ||
84 | ``` | |
85 | git clone https://github.com/ignitionrobotics/ign-math -b ign-math<#> | |
86 | ``` | |
87 | Be sure to replace `<#>` with a number value, such as 1 or 2, depending on | |
88 | which version you need. | |
89 | ||
90 | 2. Install dependencies | |
91 | ||
92 | ``` | |
93 | export SYSTEM_VERSION=bionic | |
94 | sudo apt -y install \ | |
95 | $(sort -u $(find . -iname 'packages-'$SYSTEM_VERSION'.apt' -o -iname 'packages.apt') | tr '\n' ' ') | |
96 | ``` | |
97 | ||
98 | 3. Configure and build | |
99 | ||
100 | ``` | |
101 | cd ign-math; mkdir build; cd build; cmake ..; make | |
102 | ``` | |
103 | ||
104 | 4. Optionally, install Ignition Math | |
105 | ||
106 | ``` | |
107 | sudo make install | |
108 | ``` |