Added Math.cpp + small improvement on what return some of the functions

This commit is contained in:
marcgpuig 2018-11-15 15:03:59 +01:00
parent d24ebbe7be
commit 8f7cecc6ca
2 changed files with 154 additions and 119 deletions

View File

@ -0,0 +1,128 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include "carla/geom/Math.h"
namespace carla {
namespace geom {
/// Returns a pair containing:
/// - @b first: distance from v to p' where p' = p projected on segment (w - v)
/// - @b second: Euclidean distance from p to p'
/// @param p point to calculate distance
/// @param v first point of the segment
/// @param w second point of the segment
std::pair<double, double> Math::DistSegmentPoint(
const Vector3D &p,
const Vector3D &v,
const Vector3D &w) {
const double l2 = DistanceSquared2D(v, w);
const double l = std::sqrt(l2);
if (l2 == 0.0) {
return std::make_pair(0.0, Distance2D(v, p));
}
const double dot_p_w = Dot2D(p - v, w - v);
const double t = clamp01(dot_p_w / l2);
const Vector3D projection = v + t * (w - v);
return std::make_pair(t * l, Distance2D(projection, p));
}
Vector3D Math::RotatePointOnOrigin2D(Vector3D p, double angle) {
double s = std::sin(angle);
double c = std::cos(angle);
return Vector3D(p.x * c - p.y * s, p.x * s + p.y * c, 0.0);
}
/// Returns a pair containing:
/// - @b first: distance across the arc from start_pos to p' where p' = p projected on Arc
/// - @b second: Euclidean distance from p to p'
std::pair<double, double> Math::DistArcPoint(
Vector3D p,
Vector3D start_pos,
double length,
double heading, // [radians]
double curvature) {
/// @todo: Because Unreal's coordinates, hacky way to correct
/// the -y, this must be changed in the future
p.y = -p.y;
start_pos.y = -start_pos.y;
heading = -heading;
// since this algorithm is working for positive curvatures,
// and we are only calculating distances, we can invert the y
// axis (along with the curvature and the heading), so if the
// curvature is negative, so the algorithm will work as expected
if (curvature < 0.0) {
p.y = -p.y;
start_pos.y = -start_pos.y;
heading = -heading;
curvature = -curvature;
}
// transport point relative to the arc starting poistion and rotation
const Vector3D rotated_p(RotatePointOnOrigin2D(p - start_pos, -heading));
const double radius = 1.0 / curvature;
const Vector3D circ_center(0, radius, 0);
// check if the point is in the center of the circle, so we know p
// is in the same distance of every possible point in the arc
if (rotated_p == circ_center) {
return std::make_pair(0.0, radius);
}
// find intersection position using the unit vector from the center
// of the circle to the point and multiplying by the radius
const Vector3D intersection = ((rotated_p - circ_center).MakeUnitVector() * radius) + circ_center;
// use the arc length to calculate the angle in the last point of it
// circumference of a circle = 2 * PI * r
const double circumf = 2 * pi() * radius;
const double last_point_angle = (length / circumf) * pi_double();
// move the point relative to the center of the circle and find
// the angle between the point and the center of coords in rad
double angle = std::atan2(intersection.y - radius, intersection.x) + pi_half();
if(angle < 0.0) {
angle += pi_double();
}
// see if the angle is between 0 and last_point_angle
DEBUG_ASSERT(angle >= 0.0);
if (angle <= last_point_angle) {
return std::make_pair(
angle * radius,
Distance2D(intersection, rotated_p));
}
// find the nearest point, start or end to intersection
const double start_dist = Distance2D(Vector3D(), rotated_p);
const Vector3D end_pos(
radius * std::cos(last_point_angle - pi_half()),
radius * std::sin(last_point_angle - pi_half()) + circ_center.y,
0.0);
const double end_dist = Distance2D(end_pos, rotated_p);
return (start_dist < end_dist) ?
std::make_pair(0.0, start_dist) :
std::make_pair(length, end_dist);
}
bool Math::PointInRectangle(
const Vector3D &pos,
const Vector3D &extent,
double angle, // [radians]
const Vector3D &p) {
// Move p relative to pos's position and angle
Vector3D transf_p = RotatePointOnOrigin2D(p - pos, -angle);
return transf_p.x <= extent.x && transf_p.y <= extent.y &&
transf_p.x >= -extent.x && transf_p.y >= -extent.y;
}
} // namespace geom
} // namespace carla

View File

@ -34,14 +34,16 @@ namespace geom {
return rad * (180.0 / pi());
}
static double clamp(
const double &a,
const double &min,
const double &max) {
template <typename T>
static T clamp(
const T &a,
const T &min,
const T &max) {
return std::min(std::max(a, min), max);
}
static double clamp01(double a) {
template <typename T>
static T clamp01(T a) {
return clamp(a, 0.0, 1.0);
}
@ -58,136 +60,41 @@ namespace geom {
return a.x * b.x + a.y * b.y;
}
static double DistanceSquared(const Vector3D &a, const Vector3D &b) {
return sqr<double>(b.x - a.x) + sqr<double>(b.y - a.y) + sqr<double>(b.z - a.z);
static auto DistanceSquared(const Vector3D &a, const Vector3D &b) {
return sqr(b.x - a.x) + sqr(b.y - a.y) + sqr(b.z - a.z);
}
static double DistanceSquared2D(const Vector3D &a, const Vector3D &b) {
return sqr<double>(b.x - a.x) + sqr<double>(b.y - a.y);
static auto DistanceSquared2D(const Vector3D &a, const Vector3D &b) {
return sqr(b.x - a.x) + sqr(b.y - a.y);
}
static double Distance(const Vector3D &a, const Vector3D &b) {
static auto Distance(const Vector3D &a, const Vector3D &b) {
return std::sqrt(DistanceSquared(a, b));
}
static double Distance2D(const Vector3D &a, const Vector3D &b) {
static auto Distance2D(const Vector3D &a, const Vector3D &b) {
return std::sqrt(DistanceSquared2D(a, b));
}
/// Returns a pair containing:
/// - @b first: distance from v to p' where p' = p projected on segment (w - v)
/// - @b second: Euclidean distance from p to p'
/// @param p point to calculate distance
/// @param v first point of the segment
/// @param w second point of the segment
static std::pair<double, double> DistSegmentPoint(
const Vector3D &p,
const Vector3D &v,
const Vector3D &w) {
const double l2 = DistanceSquared2D(v, w);
const double l = std::sqrt(l2);
if (l2 == 0.0) {
return std::make_pair(0.0, Distance2D(v, p));
}
const double dot_p_w = Dot2D(p - v, w - v);
const double t = clamp01(dot_p_w / l2);
const Vector3D projection = v + t * (w - v);
return std::make_pair(t * l, Distance2D(projection, p));
}
const Vector3D &,
const Vector3D &,
const Vector3D &);
static Vector3D RotatePointOnOrigin2D(Vector3D p, double angle) {
double s = std::sin(angle);
double c = std::cos(angle);
return Vector3D(p.x * c - p.y * s, p.x * s + p.y * c, 0.0);
}
static Vector3D RotatePointOnOrigin2D(Vector3D p, double angle);
/// Returns a pair containing:
/// - @b first: distance across the arc from start_pos to p' where p' = p projected on Arc
/// - @b second: Euclidean distance from p to p'
static std::pair<double, double> DistArcPoint(
Vector3D p,
Vector3D start_pos,
double length,
double heading, // [radians]
double curvature) {
/// @todo: Because Unreal's coordinates, hacky way to correct
/// the -y, this must be changed in the future
p.y = -p.y;
start_pos.y = -start_pos.y;
heading = -heading;
// since this algorithm is working for positive curvatures,
// and we are only calculating distances, we can invert the y
// axis (along with the curvature and the heading), so if the
// curvature is negative, so the algorithm will work as expected
if (curvature < 0.0) {
p.y = -p.y;
start_pos.y = -start_pos.y;
heading = -heading;
curvature = -curvature;
}
// transport point relative to the arc starting poistion and rotation
const Vector3D rotated_p(RotatePointOnOrigin2D(p - start_pos, -heading));
const double radius = 1.0 / curvature;
const Vector3D circ_center(0, radius, 0);
// check if the point is in the center of the circle, so we know p
// is in the same distance of every possible point in the arc
if (rotated_p == circ_center) {
return std::make_pair(0.0, radius);
}
// find intersection position using the unit vector from the center
// of the circle to the point and multiplying by the radius
const Vector3D intersection = ((rotated_p - circ_center).MakeUnitVector() * radius) + circ_center;
// use the arc length to calculate the angle in the last point of it
// circumference of a circle = 2 * PI * r
const double circumf = 2 * pi() * radius;
const double last_point_angle = (length / circumf) * pi_double();
// move the point relative to the center of the circle and find
// the angle between the point and the center of coords in rad
double angle = std::atan2(intersection.y - radius, intersection.x) + pi_half();
if(angle < 0.0) {
angle += pi_double();
}
// see if the angle is between 0 and last_point_angle
DEBUG_ASSERT(angle >= 0.0);
if (angle <= last_point_angle) {
return std::make_pair(
angle * radius,
Distance2D(intersection, rotated_p));
}
// find the nearest point, start or end to intersection
const double start_dist = Distance2D(Vector3D(), rotated_p);
const Vector3D end_pos(
radius * std::cos(last_point_angle - pi_half()),
radius * std::sin(last_point_angle - pi_half()) + circ_center.y,
0.0);
const double end_dist = Distance2D(end_pos, rotated_p);
return (start_dist < end_dist) ?
std::make_pair(0.0, start_dist) :
std::make_pair(length, end_dist);
}
Vector3D,
Vector3D,
double,
double, // [radians]
double);
static bool PointInRectangle(
const Vector3D &pos,
const Vector3D &extent,
double angle, // [radians]
const Vector3D &p) {
// Move p relative to pos's position and angle
Vector3D transf_p = RotatePointOnOrigin2D(p - pos, -angle);
return transf_p.x <= extent.x && transf_p.y <= extent.y &&
transf_p.x >= -extent.x && transf_p.y >= -extent.y;
}
const Vector3D &,
const Vector3D &,
double, // [radians]
const Vector3D &);
};
} // namespace geom