176 lines
5.8 KiB
C++

/*
* Software License Agreement (BSD License)
*
* Copyright (c) 2010, Willow Garage, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of the copyright holder(s) nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $Id$
*
*/
#pragma once
#include <pcl/common/intersections.h>
#include <pcl/pcl_macros.h>
#include <pcl/console/print.h>
namespace pcl
{
bool
lineWithLineIntersection (const Eigen::VectorXf &line_a,
const Eigen::VectorXf &line_b,
Eigen::Vector4f &point, double sqr_eps)
{
Eigen::Vector4f p1, p2;
lineToLineSegment (line_a, line_b, p1, p2);
// If the segment size is smaller than a pre-given epsilon...
double sqr_dist = (p1 - p2).squaredNorm ();
if (sqr_dist < sqr_eps)
{
point = p1;
return (true);
}
point.setZero ();
return (false);
}
bool
lineWithLineIntersection (const pcl::ModelCoefficients &line_a,
const pcl::ModelCoefficients &line_b,
Eigen::Vector4f &point, double sqr_eps)
{
Eigen::VectorXf coeff1 = Eigen::VectorXf::Map (&line_a.values[0], line_a.values.size ());
Eigen::VectorXf coeff2 = Eigen::VectorXf::Map (&line_b.values[0], line_b.values.size ());
return (lineWithLineIntersection (coeff1, coeff2, point, sqr_eps));
}
template <typename Scalar> bool
planeWithPlaneIntersection (const Eigen::Matrix<Scalar, 4, 1> &plane_a,
const Eigen::Matrix<Scalar, 4, 1> &plane_b,
Eigen::Matrix<Scalar, Eigen::Dynamic, 1> &line,
double angular_tolerance)
{
using Vector3 = Eigen::Matrix<Scalar, 3, 1>;
using Vector4 = Eigen::Matrix<Scalar, 4, 1>;
using Vector5 = Eigen::Matrix<Scalar, 5, 1>;
using Matrix5 = Eigen::Matrix<Scalar, 5, 5>;
// Normalize plane normals
Vector3 plane_a_norm (plane_a.template head<3> ());
Vector3 plane_b_norm (plane_b.template head<3> ());
plane_a_norm.normalize ();
plane_b_norm.normalize ();
// Test if planes are parallel
double test_cos = plane_a_norm.dot (plane_b_norm);
double tolerance_cos = 1 - sin (std::abs (angular_tolerance));
if (std::abs (test_cos) > tolerance_cos)
{
PCL_DEBUG ("Plane A and Plane B are parallel.\n");
return (false);
}
Vector4 line_direction = plane_a.cross3 (plane_b);
line_direction.normalized();
// Construct system of equations using lagrange multipliers with one objective function and two constraints
Matrix5 langrange_coefs;
langrange_coefs << 2,0,0, plane_a[0], plane_b[0],
0,2,0, plane_a[1], plane_b[1],
0,0,2, plane_a[2], plane_b[2],
plane_a[0], plane_a[1], plane_a[2], 0, 0,
plane_b[0], plane_b[1], plane_b[2], 0, 0;
Vector5 b;
b << 0, 0, 0, -plane_a[3], -plane_b[3];
line.resize(6);
// Solve for the lagrange multipliers
line.template head<3>() = langrange_coefs.colPivHouseholderQr().solve(b).template head<3> ();
line.template tail<3>() = line_direction.template head<3>();
return (true);
}
template <typename Scalar> bool
threePlanesIntersection (const Eigen::Matrix<Scalar, 4, 1> &plane_a,
const Eigen::Matrix<Scalar, 4, 1> &plane_b,
const Eigen::Matrix<Scalar, 4, 1> &plane_c,
Eigen::Matrix<Scalar, 3, 1> &intersection_point,
double determinant_tolerance)
{
using Vector3 = Eigen::Matrix<Scalar, 3, 1>;
using Matrix3 = Eigen::Matrix<Scalar, 3, 3>;
// TODO: Using Eigen::HyperPlanes is better to solve this problem
// Check if some planes are parallel
Matrix3 normals_in_lines;
for (int i = 0; i < 3; i++)
{
normals_in_lines (i, 0) = plane_a[i];
normals_in_lines (i, 1) = plane_b[i];
normals_in_lines (i, 2) = plane_c[i];
}
Scalar determinant = normals_in_lines.determinant ();
if (std::abs (determinant) < determinant_tolerance)
{
// det ~= 0
PCL_DEBUG ("At least two planes are parallel.\n");
return (false);
}
// Left part of the 3 equations
Matrix3 left_member;
for (int i = 0; i < 3; i++)
{
left_member (0, i) = plane_a[i];
left_member (1, i) = plane_b[i];
left_member (2, i) = plane_c[i];
}
// Right side of the 3 equations
Vector3 right_member;
right_member << -plane_a[3], -plane_b[3], -plane_c[3];
// Solve the system
intersection_point = left_member.fullPivLu ().solve (right_member);
return (true);
}
} // namespace pcl