RoboDK Plug-In Interface
Loading...
Searching...
No Matches
matrix4x4.cpp
1/****************************************************************************
2**
3** Copyright (c) 2015-2025 RoboDK Inc.
4** Contact: https://robodk.com/
5**
6** This file is part of the RoboDK API.
7**
8** Permission is hereby granted, free of charge, to any person obtaining a copy
9** of this software and associated documentation files (the "Software"), to deal
10** in the Software without restriction, including without limitation the rights
11** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12** copies of the Software, and to permit persons to whom the Software is
13** furnished to do so, subject to the following conditions:
14**
15** The above copyright notice and this permission notice shall be included in all
16** copies or substantial portions of the Software.
17**
18** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24** SOFTWARE.
25**
26** RoboDK is a registered trademark of RoboDK Inc.
27**
28****************************************************************************/
29
30#include "matrix4x4.h"
31
32#include <cmath>
33
34#include "vector3.h"
35#include "constants.h"
36
37
38namespace robodk
39{
40
42 : QMatrix4x4()
43 , _valid(true)
44{
45 setToIdentity();
46}
47
49 : QMatrix4x4()
50 , _valid(valid ? 1.0 : 0.0)
51{
52 setToIdentity();
53}
54
56 : QMatrix4x4(matrix)
57 , _valid(matrix._valid)
58{
59}
60
61Matrix4x4::Matrix4x4(const double* values)
62 : QMatrix4x4(
63 values[0], values[4], values[8], values[12],
64 values[1], values[5], values[9], values[13],
65 values[2], values[6], values[10], values[14],
66 values[3], values[7], values[11], values[15])
67 , _valid(1.0)
68{
69}
70
71Matrix4x4::Matrix4x4(const float* values)
72 : QMatrix4x4(
73 values[0], values[4], values[8], values[12],
74 values[1], values[5], values[9], values[13],
75 values[2], values[6], values[10], values[14],
76 values[3], values[7], values[11], values[15])
77 , _valid(1.0)
78{
79}
80
81Matrix4x4::Matrix4x4(double x, double y, double z)
82 : QMatrix4x4(
83 1.0f, 0.0f, 0.0f, x,
84 0.0f, 1.0f, 0.0f, y,
85 0.0f, 0.0f, 1.0f, z,
86 0.0f, 0.0f, 0.0f, 1.0f)
87 , _valid(1.0)
88{
89 setToIdentity();
90 (*this)(0, 3) = x;
91 (*this)(1, 3) = y;
92 (*this)(2, 3) = z;
93}
94
95
97 double nx,
98 double ox,
99 double ax,
100 double tx,
101 double ny,
102 double oy,
103 double ay,
104 double ty,
105 double nz,
106 double oz,
107 double az,
108 double tz)
109 : QMatrix4x4(
110 nx, ox, ax, tx,
111 ny, oy, ay, ty,
112 nz, oz, az, tz,
113 0.0f, 0.0f, 0.0f, 1.0f)
114 , _valid(1.0)
115{
116}
117
119{
120 (*this)(0, 0) = n.X();
121 (*this)(1, 0) = n.Y();
122 (*this)(2, 0) = n.Z();
123}
124
126{
127 (*this)(0, 1) = o.X();
128 (*this)(1, 1) = o.Y();
129 (*this)(2, 1) = o.Z();
130}
131
133{
134 (*this)(0, 2) = a.X();
135 (*this)(1, 2) = a.Y();
136 (*this)(2, 2) = a.Z();
137}
138
139void Matrix4x4::SetVX(double x, double y, double z)
140{
141 Set(0,0, x);
142 Set(1,0, y);
143 Set(2,0, z);
144}
145
146void Matrix4x4::SetVY(double x, double y, double z)
147{
148 Set(0,1, x);
149 Set(1,1, y);
150 Set(2,1, z);
151}
152
153void Matrix4x4::SetVZ(double x, double y, double z)
154{
155 Set(0,2, x);
156 Set(1,2, y);
157 Set(2,2, z);
158}
159
160void Matrix4x4::SetPos(double x, double y, double z)
161{
162 Set(0, 3, x);
163 Set(1, 3, y);
164 Set(2, 3, z);
165}
166
167void Matrix4x4::SetVX(const double* xyz)
168{
169 Set(0, 0, xyz[0]);
170 Set(1, 0, xyz[1]);
171 Set(2, 0, xyz[2]);
172}
173
174void Matrix4x4::SetVY(const double* xyz)
175{
176 Set(0, 1, xyz[0]);
177 Set(1, 1, xyz[1]);
178 Set(2, 1, xyz[2]);
179}
180
181void Matrix4x4::SetVZ(const double* xyz)
182{
183 Set(0, 2, xyz[0]);
184 Set(1, 2, xyz[1]);
185 Set(2, 2, xyz[2]);
186}
187
188void Matrix4x4::SetPos(const double* xyz)
189{
190 Set(0, 3, xyz[0]);
191 Set(1, 3, xyz[1]);
192 Set(2, 3, xyz[2]);
193}
194
196{
197 return Vector3(
198 Get(0, 0),
199 Get(1, 0),
200 Get(2, 0));
201}
202
204{
205 return Vector3(
206 Get(0, 1),
207 Get(1, 1),
208 Get(2, 1));
209}
210
212{
213 return Vector3(
214 Get(0, 2),
215 Get(1, 2),
216 Get(2, 2));
217}
218
219void Matrix4x4::VX(double* xyz) const
220{
221 xyz[0] = Get(0, 0);
222 xyz[1] = Get(1, 0);
223 xyz[2] = Get(2, 0);
224}
225
226void Matrix4x4::VY(double* xyz) const
227{
228 xyz[0] = Get(0, 1);
229 xyz[1] = Get(1, 1);
230 xyz[2] = Get(2, 1);
231}
232
233void Matrix4x4::VZ(double* xyz) const
234{
235 xyz[0] = Get(0, 2);
236 xyz[1] = Get(1, 2);
237 xyz[2] = Get(2, 2);
238}
239
240void Matrix4x4::Pos(double* xyz) const
241{
242 xyz[0] = Get(0, 3);
243 xyz[1] = Get(1, 3);
244 xyz[2] = Get(2, 3);
245}
246
247void Matrix4x4::SetValues(const double* values)
248{
249 Set(0, 0, values[0]);
250 Set(1, 0, values[1]);
251 Set(2, 0, values[2]);
252 Set(3, 0, values[3]);
253
254 Set(0, 1, values[4]);
255 Set(1, 1, values[5]);
256 Set(2, 1, values[6]);
257 Set(3, 1, values[7]);
258
259 Set(0, 2, values[8]);
260 Set(1, 2, values[9]);
261 Set(2, 2, values[10]);
262 Set(3, 2, values[11]);
263
264 Set(0, 3, values[12]);
265 Set(1, 3, values[13]);
266 Set(2, 3, values[14]);
267 Set(3, 3, values[15]);
268}
269
270void Matrix4x4::Set(int row, int column, double value)
271{
272 (*this)(row, column) = value;
273}
274
275double Matrix4x4::Get(int row, int column) const
276{
277 return (*this)(row, column);
278}
279
280Matrix4x4 Matrix4x4::Inverted(bool* invertible) const
281{
282 return this->inverted(invertible);
283}
284
286{
287 auto tx = VX();
288 auto ty = VY();
289 auto tz = VZ();
290
291 const double tol = 1e-7;
292
293 if (std::fabs(Vector3::DotProduct(tx, ty)) > tol)
294 {
295 return false;
296 }
297 else if (std::fabs(Vector3::DotProduct(tx, tz)) > tol)
298 {
299 return false;
300 }
301 else if (std::fabs(Vector3::DotProduct(ty, tz)) > tol)
302 {
303 return false;
304 }
305 else if (std::fabs(tx.Length() - 1.0) > tol)
306 {
307 return false;
308 }
309 else if (std::fabs(ty.Length() - 1.0) > tol)
310 {
311 return false;
312 }
313 else if (std::fabs(tz.Length() - 1.0) > tol)
314 {
315 return false;
316 }
317
318 return true;
319}
320
322{
323 auto tx = VX();
324 auto ty = VY();
325 auto tz = VZ();
326
327 bool result = IsHomogeneous();
328
329 tx.Normalize();
330 tz = Vector3::CrossProduct(tx, ty);
331 tz.Normalize();
332 ty = Vector3::CrossProduct(tz, tx);
333 ty.Normalize();
334
335 SetVX(tx);
336 SetVY(ty);
337 SetVZ(tz);
338
339 (*this)(3, 0) = 0.0f;
340 (*this)(3, 1) = 0.0f;
341 (*this)(3, 2) = 0.0f;
342 (*this)(3, 3) = 1.0f;
343
344 return !result;
345}
346
347void Matrix4x4::ToXYZRPW(double* xyzwpr) const
348{
349 double x = Get(0, 3);
350 double y = Get(1, 3);
351 double z = Get(2, 3);
352 double w, p, r;
353
354 if (Get(2,0) > (1.0 - 1e-6))
355 {
356 p = -constants::pi * 0.5;
357 r = 0;
358 w = atan2(-Get(1,2), Get(1,1));
359 }
360 else if (Get(2,0) < -1.0 + 1e-6)
361 {
362 p = 0.5 * constants::pi;
363 r = 0;
364 w = atan2(Get(1,2),Get(1,1));
365 }
366 else
367 {
368 p = atan2(-Get(2, 0), sqrt(Get(0, 0) * Get(0, 0) + Get(1, 0) * Get(1, 0)));
369 w = atan2(Get(1, 0), Get(0, 0));
370 r = atan2(Get(2, 1), Get(2, 2));
371 }
372
373 xyzwpr[0] = x;
374 xyzwpr[1] = y;
375 xyzwpr[2] = z;
376 xyzwpr[3] = r * 180.0 / constants::pi;
377 xyzwpr[4] = p * 180.0 / constants::pi;
378 xyzwpr[5] = w * 180.0 / constants::pi;
379}
380
381Matrix4x4 Matrix4x4::XYZRPW_2_Mat(double x, double y, double z, double r, double p, double w)
382{
383 double a = r * constants::pi / 180.0;
384 double b = p * constants::pi / 180.0;
385 double c = w * constants::pi / 180.0;
386 double ca = cos(a);
387 double sa = sin(a);
388 double cb = cos(b);
389 double sb = sin(b);
390 double cc = cos(c);
391 double sc = sin(c);
392 return Matrix4x4(cb * cc, cc * sa * sb - ca * sc, sa * sc + ca * cc * sb, x,
393 cb * sc, ca * cc + sa * sb * sc, ca * sb * sc - cc * sa, y,
394 -sb, cb * sa, ca * cb, z);
395}
396
398{
399 return XYZRPW_2_Mat(xyzwpr[0], xyzwpr[1], xyzwpr[2], xyzwpr[3], xyzwpr[4], xyzwpr[5]);
400}
401
402void Matrix4x4::FromXYZRPW(const double* xyzwpr)
403{
404 Matrix4x4 newmat = Matrix4x4::XYZRPW_2_Mat(xyzwpr[0], xyzwpr[1], xyzwpr[2],
405 xyzwpr[3], xyzwpr[4], xyzwpr[5]);
406
407 for (int i = 0; i < 4; i++)
408 {
409 for (int j = 0; j < 4; j++)
410 {
411 this->Set(i, j, newmat.Get(i, j));
412 }
413 }
414}
415
416const double* Matrix4x4::ValuesD() const
417{
418 for(int i = 0; i < 16; ++i)
419 {
420 _md[i] = constData()[i];
421 }
422 return _md;
423}
424
425const float* Matrix4x4::ValuesF() const
426{
427 return constData();
428}
429
430#ifdef ROBODK_API_FLOATS
431const float* Matrix4x4::Values() const
432{
433 return constData();
434}
435#else
436const double* Matrix4x4::Values() const
437{
438 return ValuesD();
439}
440#endif
441
442void Matrix4x4::Values(double* data) const
443{
444 for(int i = 0; i < 16; ++i)
445 {
446 data[i] = constData()[i];
447 }
448}
449
450void Matrix4x4::Values(float* data) const
451{
452 for(int i = 0; i < 16; ++i)
453 {
454 data[i] = constData()[i];
455 }
456}
457
459{
460 return _valid;
461}
462
464{
465 QMatrix4x4::operator=(matrix);
466 _valid = 1.0;
467 return *this;
468}
469
470Matrix4x4 Matrix4x4::transl(double x, double y, double z)
471{
472 Matrix4x4 mat;
473 mat.setToIdentity();
474 mat.SetPos(x, y, z);
475 return mat;
476}
477
479{
480 double cx = cos(rx);
481 double sx = sin(rx);
482 return Matrix4x4(1, 0, 0, 0, 0, cx, -sx, 0, 0, sx, cx, 0);
483}
484
486{
487 double cy = cos(ry);
488 double sy = sin(ry);
489 return Matrix4x4(cy, 0, sy, 0, 0, 1, 0, 0, -sy, 0, cy, 0);
490}
491
493{
494 double cz = cos(rz);
495 double sz = sin(rz);
496 return Matrix4x4(cz, -sz, 0, 0, sz, cz, 0, 0, 0, 0, 1, 0);
497}
498
499#ifdef QT_GUI_LIB
500Matrix4x4::Matrix4x4(const QMatrix4x4 &matrix)
501 : QMatrix4x4(matrix)
502 , _valid(1.0)
503{
504}
505
506bool Matrix4x4::FromString(const QString &pose_str)
507{
508 QString pose_str2 = pose_str.trimmed();
509
510 const Qt::CaseSensitivity cs = Qt::CaseInsensitive;
511 if (pose_str2.startsWith("Mat(", cs))
512 {
513 pose_str2.remove(0, 4);
514 pose_str2 = pose_str2.trimmed();
515 }
516
517 if (pose_str2.startsWith("XYZRPW_2_Mat(", cs))
518 {
519 pose_str2.remove(0, 13);
520 pose_str2 = pose_str2.trimmed();
521 }
522
523 while (pose_str2.endsWith(')'))
524 {
525 pose_str2.chop(1);
526 }
527
528 const QLatin1Char separator(',');
529 pose_str2.replace(QLatin1Char(';'), separator);
530 pose_str2.replace(QLatin1Char('\t'), separator);
531
532#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0))
533 const QString::SplitBehavior behavior = QString::SkipEmptyParts;
534#else
535 const Qt::SplitBehavior behavior = Qt::SkipEmptyParts;
536#endif
537
538 QStringList values_list = pose_str2.split(separator, behavior);
539 double xyzwpr[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
540
541 if (values_list.length() < 6)
542 {
543 FromXYZRPW(xyzwpr);
544 return false;
545 }
546
547 for (int i = 0; i < 6; i++)
548 {
549 xyzwpr[i] = values_list[i].trimmed().toDouble();
550 }
551
552 FromXYZRPW(xyzwpr);
553 return true;
554}
555
556QString Matrix4x4::ToString(const QString &separator, int precision, bool xyzrpwOnly) const
557{
558 if (!Valid())
559 {
560 return "Mat(Invalid)";
561 }
562
563 QString str;
564 if (!IsHomogeneous())
565 {
566 str.append("Warning!! Pose is not homogeneous! Use Matrix4x4::MakeHomogeneous() to make this matrix homogeneous\n");
567 }
568
569 str.append("Mat(XYZRPW_2_Mat(");
570
571 double xyzwpr[6];
572 ToXYZRPW(xyzwpr);
573
574 for (int i = 0; i < 6; i++)
575 {
576 if (i > 0)
577 {
578 str.append(separator);
579 }
580 str.append(QString::number(xyzwpr[i], 'f', precision));
581 }
582 str.append("))");
583
584 if (xyzrpwOnly)
585 {
586 return str;
587 }
588
589 str.append("\n");
590
591 for (int i = 0; i < 4; i++)
592 {
593 str.append("[");
594 for (int j = 0; j < 4; j++)
595 {
596 str.append(QString::number(row(i)[j], 'f', precision));
597 if (j < 3)
598 {
599 str.append(separator);
600 }
601 }
602 str.append("];\n");
603 }
604 return str;
605}
606
607Matrix4x4& Matrix4x4::operator=(const QMatrix4x4& matrix)
608{
609 QMatrix4x4::operator=(matrix);
610 _valid = 1.0;
611 return *this;
612}
613#endif // QT_GUI_LIB
614
615} // namespace robodk
The Matrix4x4 class represents a 4x4 transformation matrix in 3D space.
Definition matrix4x4.h:70
Vector3 VX() const
Returns the X vector (N vector).
void SetVZ(const Vector3 &a)
Sets the Z vector (A vector).
void SetVY(const Vector3 &o)
Sets the Y vector (O vector).
static Matrix4x4 transl(double x, double y, double z)
Constructs a matrix that translates coordinates by the components x, y, and z.
void ToXYZRPW(double *xyzwpr) const
Calculates the position and euler angles ([x,y,z,r,p,w] vector) from this matrix.
void Pos(double *xyz) const
Writes the position (T vector) into array of 3 double-precision xyz values.
Vector3 VY() const
Returns the Y vector (O vector).
static Matrix4x4 rotx(double rx)
Constructs a matrix that rotates coordinates around X axis.
bool Valid() const
Returns true if the matrix is marked as valid; false otherwise.
void FromXYZRPW(const double *xyzwpr)
Calculates this matrix from the position and euler angles ([x,y,z,r,p,w] vector).
static Matrix4x4 rotz(double rz)
Constructs a matrix that rotates coordinates around Z axis.
const double * Values() const
Returns a constant pointer to the raw data of this matrix as 16 double- or single-precision numbers.
Matrix4x4()
Constructs an identity matrix.
Definition matrix4x4.cpp:41
Matrix4x4 & operator=(const Matrix4x4 &matrix)
Sets this Matrix4x4 object as a copy of matrix.
void SetValues(const double *values)
Sets the elements of matrix from the given 16 double-precision values.
void SetVX(const Vector3 &n)
Sets the X vector (N vector).
void SetPos(double x, double y, double z)
Sets the position (T).
bool MakeHomogeneous()
Forces this matrix to be homogeneous.
static Matrix4x4 roty(double ry)
Constructs a matrix that rotates coordinates around Y axis.
const double * ValuesD() const
Returns a constant pointer to the raw data of this matrix as 16 double-precision numbers.
Matrix4x4 Inverted(bool *invertible=nullptr) const
Returns the inverse of this matrix.
void Set(int row, int column, double value)
Sets a new value to the element at position (row, column) in this matrix.
static Matrix4x4 XYZRPW_2_Mat(double x, double y, double z, double r, double p, double w)
Constructs a matrix from the position and euler angles ([x,y,z,r,p,w] vector).
Vector3 VZ() const
Returns the Z vector (A vector).
const float * ValuesF() const
Returns a constant pointer to the raw data of this matrix as 16 single-precision numbers.
double Get(int row, int column) const
Returns the value of the element at position (row, column) in this matrix.
bool IsHomogeneous() const
Returns true if the matrix is homogeneous; false otherwise.
The Vector3 class represents a vector or vertex in 3D space.
Definition vector3.h:49
static double DotProduct(const Vector3 &v1, const Vector3 &v2)
Returns the dot product of v1 and v2.
Definition vector3.cpp:61
static Vector3 CrossProduct(const Vector3 &v1, const Vector3 &v2)
Returns the cross-product of vectors v1 and v2, which corresponds to the normal vector of a plane def...
Definition vector3.cpp:66
double Z() const
Returns the z coordinate of this vector.
Definition vector3.h:90
double X() const
Returns the x coordinate of this vector.
Definition vector3.h:80
double Y() const
Returns the y coordinate of this vector.
Definition vector3.h:85