Skip to content

Commit 71ecea3

Browse files
Best Fit Plane - Change to Y-axis for look-at matrix
GitHub issue #269.
1 parent a9a84f4 commit 71ecea3

File tree

4 files changed

+128
-12
lines changed

4 files changed

+128
-12
lines changed

lib/cppbind/mmcore/include/mmcore/mmmath.h

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,30 @@ bool infiniteLineIntersection(mmdata::Point2D pointA, mmdata::Point2D pointB,
232232
*/
233233
double cosineAngleBetweenLines(mmdata::LinePair2D linePair);
234234

235+
/**
236+
* Create look-at matrix from direction vector.
237+
*
238+
* Result aligns X axis with direction and maintains Y axis up where
239+
* possible.
240+
*
241+
* @param dir Direction vector to look at
242+
* @param out_matrix Resulting orientation matrix
243+
*/
244+
void createLookAtMatrixAxisX(const mmdata::Vector3D &dir,
245+
mmdata::Matrix4x4 &out_matrix);
246+
247+
/**
248+
* Create look-at matrix from direction vector.
249+
*
250+
* Result aligns Y axis with direction and maintains Y axis up where
251+
* possible.
252+
*
253+
* @param dir Direction vector to look at
254+
* @param out_matrix Resulting orientation matrix
255+
*/
256+
void createLookAtMatrixAxisY(const mmdata::Vector3D &dir,
257+
mmdata::Matrix4x4 &out_matrix);
258+
235259
/**
236260
* Create look-at matrix from direction vector.
237261
*
@@ -241,8 +265,8 @@ double cosineAngleBetweenLines(mmdata::LinePair2D linePair);
241265
* @param dir Direction vector to look at
242266
* @param out_matrix Resulting orientation matrix
243267
*/
244-
void createLookAtMatrix(const mmdata::Vector3D &dir,
245-
mmdata::Matrix4x4 &out_matrix);
268+
void createLookAtMatrixAxisZ(const mmdata::Vector3D &dir,
269+
mmdata::Matrix4x4 &out_matrix);
246270

247271
} // namespace mmmath
248272

lib/cppbind/mmcore/src/mmmath.cpp

Lines changed: 94 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -498,30 +498,116 @@ double cosineAngleBetweenLines(mmdata::LinePair2D linePair) {
498498
return angle_cosine;
499499
}
500500

501-
void createLookAtMatrix(const mmdata::Vector3D &dir,
502-
mmdata::Matrix4x4 &out_matrix) {
501+
// Implementation detail. Do not reveal this to users of the API.
502+
void impl_createLookAtMatrix(const mmdata::Vector3D &dir,
503+
const mmdata::Vector3D &temp_up,
504+
mmdata::Vector3D &out_forward,
505+
mmdata::Vector3D &out_right,
506+
mmdata::Vector3D &out_up) {
507+
out_forward.x_ = dir.x_;
508+
out_forward.y_ = dir.y_;
509+
out_forward.z_ = dir.z_;
510+
out_forward = mmmath::normalize(out_forward);
511+
512+
out_right = mmmath::cross(temp_up, out_forward);
513+
out_right = mmmath::normalize(out_right);
514+
515+
out_up = mmmath::cross(out_forward, out_right);
516+
out_up = mmmath::normalize(out_up);
517+
}
518+
519+
void createLookAtMatrixAxisX(const mmdata::Vector3D &dir,
520+
mmdata::Matrix4x4 &out_matrix) {
503521
const auto temp_up = mmdata::Vector3D(0.0, 1.0, 0.0);
522+
auto forward = mmdata::Vector3D();
523+
auto right = mmdata::Vector3D();
524+
auto up = mmdata::Vector3D();
525+
impl_createLookAtMatrix(dir, temp_up, forward, right, up);
526+
527+
// X axis. Looking towards this axis.
528+
out_matrix.m00_ = forward.x_;
529+
out_matrix.m01_ = forward.y_;
530+
out_matrix.m02_ = forward.z_;
531+
out_matrix.m03_ = 0.0;
532+
533+
// Y axis.
534+
out_matrix.m10_ = up.x_;
535+
out_matrix.m11_ = up.y_;
536+
out_matrix.m12_ = up.z_;
537+
out_matrix.m13_ = 0.0;
538+
539+
// Z axis.
540+
out_matrix.m20_ = right.x_;
541+
out_matrix.m21_ = right.y_;
542+
out_matrix.m22_ = right.z_;
543+
out_matrix.m23_ = 0.0;
544+
545+
// Translations (unused).
546+
out_matrix.m30_ = 0.0;
547+
out_matrix.m31_ = 0.0;
548+
out_matrix.m32_ = 0.0;
549+
out_matrix.m33_ = 1.0;
550+
}
551+
552+
void createLookAtMatrixAxisY(const mmdata::Vector3D &dir,
553+
mmdata::Matrix4x4 &out_matrix) {
554+
auto forward = mmdata::Vector3D();
555+
auto right = mmdata::Vector3D();
556+
auto up = mmdata::Vector3D();
557+
const auto temp_up = mmdata::Vector3D(0.0, 0.0, 1.0);
558+
impl_createLookAtMatrix(dir, temp_up, forward, right, up);
504559

505-
auto forward = mmdata::Vector3D(dir.x_, dir.y_, dir.z_);
506-
forward = mmmath::normalize(forward);
560+
// X axis.
561+
out_matrix.m00_ = right.x_;
562+
out_matrix.m01_ = right.y_;
563+
out_matrix.m02_ = right.z_;
564+
out_matrix.m03_ = 0.0;
507565

508-
auto right = mmmath::cross(temp_up, forward);
509-
right = mmmath::normalize(right);
566+
// Y axis. Looking towards this axis.
567+
out_matrix.m10_ = forward.x_;
568+
out_matrix.m11_ = forward.y_;
569+
out_matrix.m12_ = forward.z_;
570+
out_matrix.m13_ = 0.0;
510571

511-
auto up = mmmath::cross(forward, right);
512-
up = mmmath::normalize(up);
572+
// Z axis.
573+
out_matrix.m20_ = up.x_;
574+
out_matrix.m21_ = up.y_;
575+
out_matrix.m22_ = up.z_;
576+
out_matrix.m23_ = 0.0;
513577

578+
// Translations (unused).
579+
out_matrix.m30_ = 0.0;
580+
out_matrix.m31_ = 0.0;
581+
out_matrix.m32_ = 0.0;
582+
out_matrix.m33_ = 1.0;
583+
}
584+
585+
void createLookAtMatrixAxisZ(const mmdata::Vector3D &dir,
586+
mmdata::Matrix4x4 &out_matrix) {
587+
auto forward = mmdata::Vector3D();
588+
auto right = mmdata::Vector3D();
589+
auto up = mmdata::Vector3D();
590+
const auto temp_up = mmdata::Vector3D(0.0, 1.0, 0.0);
591+
impl_createLookAtMatrix(dir, temp_up, forward, right, up);
592+
593+
// X axis.
514594
out_matrix.m00_ = right.x_;
515595
out_matrix.m01_ = right.y_;
516596
out_matrix.m02_ = right.z_;
517597
out_matrix.m03_ = 0.0;
598+
599+
// Y axis.
518600
out_matrix.m10_ = up.x_;
519601
out_matrix.m11_ = up.y_;
520602
out_matrix.m12_ = up.z_;
521603
out_matrix.m13_ = 0.0;
604+
605+
// Z axis. Looking towards this axis.
522606
out_matrix.m20_ = forward.x_;
523607
out_matrix.m21_ = forward.y_;
524608
out_matrix.m22_ = forward.z_;
609+
610+
// Translations (unused).
525611
out_matrix.m23_ = 0.0;
526612
out_matrix.m30_ = 0.0;
527613
out_matrix.m31_ = 0.0;

lib/rust/mmscenegraph/src/math/fit_plane.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,13 @@ pub fn fit_plane_to_points(points_xyz: &[f64]) -> Option<PlaneFit> {
103103
Some(u_value) => {
104104
// The normal vector is the last left singular vector
105105
// (corresponding to smallest singular value).
106-
let normal = u_value.column(2).normalize();
106+
let mut normal = u_value.column(2).normalize();
107+
108+
// Ensure the normal points towards +Y axis.
109+
let up_axis = Vector3::new(0.0, 1.0, 0.0);
110+
if normal.dot(&up_axis) <= 0.0 {
111+
normal.neg_mut();
112+
}
107113

108114
// Calculate RMS error.
109115
let rms_error = calculate_rms_error(points_xyz, &normal, &position);

src/mmSolver/cmd/MMBestFitPlaneCmd.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ MStatus MMBestFitPlaneCmd::doIt(const MArgList &args) {
260260
mmdata::Matrix4x4 matrix;
261261
const mmdata::Vector3D dir(plane_normal_x, plane_normal_y,
262262
plane_normal_z);
263-
mmmath::createLookAtMatrix(dir, matrix);
263+
mmmath::createLookAtMatrixAxisY(dir, matrix);
264264
matrix.m30_ = plane_position_x;
265265
matrix.m31_ = plane_position_y;
266266
matrix.m32_ = plane_position_z;

0 commit comments

Comments
 (0)