2012-02-06 16:44:09 +01:00
|
|
|
/*
|
2013-05-29 18:43:35 +02:00
|
|
|
* This file is part of the Owl Positioning System (OwlPS) project.
|
|
|
|
* It is subject to the copyright notice and license terms in the
|
|
|
|
* COPYRIGHT.t2t file found in the top-level directory of this
|
|
|
|
* distribution and at
|
|
|
|
* http://code.lm7.fr/p/owlps/source/tree/master/COPYRIGHT.t2t
|
|
|
|
* No part of the OwlPS Project, including this file, may be copied,
|
|
|
|
* modified, propagated, or distributed except according to the terms
|
|
|
|
* contained in the COPYRIGHT.t2t file; the COPYRIGHT.t2t file must be
|
|
|
|
* distributed along with this file, either separately or by replacing
|
2013-06-22 23:30:17 +02:00
|
|
|
* this notice by the COPYRIGHT.t2t file's contents.
|
2012-02-06 16:44:09 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
2009-12-07 16:03:53 +01:00
|
|
|
#include "point3d.hh"
|
2014-05-13 01:15:34 +02:00
|
|
|
#include "timestamp.hh"
|
2011-07-13 15:00:54 +02:00
|
|
|
#include "posutil.hh"
|
2011-04-27 18:47:56 +02:00
|
|
|
#include "posexcept.hh"
|
2009-12-07 16:03:53 +01:00
|
|
|
|
2010-02-04 18:46:23 +01:00
|
|
|
#include <sstream>
|
2009-12-07 16:03:53 +01:00
|
|
|
|
2013-07-03 16:39:10 +02:00
|
|
|
// For interpolate()
|
|
|
|
#include <claw/tween/tweener_group.hpp>
|
|
|
|
#include <claw/tween/single_tweener.hpp>
|
|
|
|
#include <claw/tween/easing/easing_linear.hpp>
|
|
|
|
|
2011-04-27 18:47:56 +02:00
|
|
|
using namespace std ;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* *** Constructors *** */
|
|
|
|
|
|
|
|
|
|
|
|
Point3D::Point3D(const string &source)
|
|
|
|
{
|
|
|
|
float pos[3] ;
|
|
|
|
istringstream iss(source) ;
|
|
|
|
|
|
|
|
for (int i = 0 ; i < 2 ; ++i)
|
|
|
|
{
|
|
|
|
iss >> pos[i] ;
|
|
|
|
if (iss.get() != ';')
|
|
|
|
throw malformed_input_data(
|
|
|
|
"Point3D(string): cannot extract coordinates!") ;
|
|
|
|
}
|
|
|
|
iss >> pos[2] ;
|
|
|
|
|
|
|
|
set_coordinates(pos) ;
|
|
|
|
}
|
|
|
|
|
2009-12-07 16:03:53 +01:00
|
|
|
|
|
|
|
|
2010-01-16 12:23:07 +01:00
|
|
|
/* *** Distance operations *** */
|
2009-12-07 16:03:53 +01:00
|
|
|
|
|
|
|
|
2012-04-27 15:28:55 +02:00
|
|
|
/**
|
|
|
|
* The distance is not square rooted after the computation, in order
|
|
|
|
* to optimise comparisons.
|
|
|
|
*/
|
|
|
|
float Point3D::square_distance_2d(const Point3D &source) const
|
|
|
|
{
|
|
|
|
return
|
|
|
|
(x - source.x) * (x - source.x) +
|
|
|
|
(y - source.y) * (y - source.y) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-16 12:23:07 +01:00
|
|
|
/**
|
|
|
|
* The distance is not square rooted after the computation, in order
|
|
|
|
* to optimise comparisons.
|
2009-12-07 16:03:53 +01:00
|
|
|
*/
|
2010-02-03 13:40:27 +01:00
|
|
|
float Point3D::square_distance(const Point3D &source) const
|
2009-12-07 16:03:53 +01:00
|
|
|
{
|
|
|
|
return
|
2010-02-03 13:40:27 +01:00
|
|
|
(x - source.x) * (x - source.x) +
|
|
|
|
(y - source.y) * (y - source.y) +
|
|
|
|
(z - source.z) * (z - source.z) ;
|
2009-12-07 16:03:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-13 15:00:54 +02:00
|
|
|
/**
|
|
|
|
* A, B and C are three points, A being the current Point3D (*this).
|
2012-04-27 15:30:25 +02:00
|
|
|
* This function computes the angle BÂC, in two dimensions (i.e. the Z
|
|
|
|
* coordinate of the points is ignored).
|
|
|
|
*
|
2011-07-18 13:35:02 +02:00
|
|
|
* If the points are aligned, the angle returned is always 0° (and not
|
2012-04-27 15:30:25 +02:00
|
|
|
* 180°, even in the case where A is on [BC]).
|
|
|
|
*
|
|
|
|
* @returns The angle BÂC, in the interval [0, 180[ degrees.
|
2011-07-13 15:00:54 +02:00
|
|
|
*/
|
2012-04-27 15:30:25 +02:00
|
|
|
double Point3D::angle_2d(const Point3D &b, const Point3D &c) const
|
2011-07-13 15:00:54 +02:00
|
|
|
{
|
2011-07-18 13:35:02 +02:00
|
|
|
double
|
2012-04-27 15:30:25 +02:00
|
|
|
sq_ab = square_distance_2d(b),
|
|
|
|
sq_ac = square_distance_2d(c),
|
|
|
|
sq_bc = b.square_distance_2d(c) ;
|
2011-07-13 15:00:54 +02:00
|
|
|
|
2011-07-18 13:35:02 +02:00
|
|
|
if (sq_ab == 0 || sq_ac == 0 || sq_bc == 0)
|
|
|
|
return 0 ;
|
|
|
|
|
2014-05-14 21:50:23 +02:00
|
|
|
double ab = sqrt(sq_ab) ;
|
|
|
|
double ac = sqrt(sq_ac) ;
|
2011-07-18 13:35:02 +02:00
|
|
|
|
2011-07-13 15:00:54 +02:00
|
|
|
double cos_bac = (sq_ab + sq_ac - sq_bc) / (2 * ab * ac) ;
|
|
|
|
double bac = acos(cos_bac) ;
|
|
|
|
|
|
|
|
return PosUtil::rad2deg(bac) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-30 09:58:30 +02:00
|
|
|
/**
|
|
|
|
* #x and #y are updated with the rotated image of the point.
|
|
|
|
*
|
|
|
|
* Note that as this functions does a 2D rotation, the c.z is ignored,
|
|
|
|
* and so is this->x.
|
|
|
|
*/
|
|
|
|
void Point3D::rotate_2d(const Point3D &c, float angle)
|
|
|
|
{
|
|
|
|
angle = PosUtil::deg2rad(angle) ;
|
|
|
|
|
|
|
|
float new_x = cos(angle) * (x-c.x) - sin(angle) * (y-c.y) + c.x ;
|
|
|
|
float new_y = sin(angle) * (x-c.x) + cos(angle) * (y-c.y) + c.y ;
|
|
|
|
|
|
|
|
x = new_x ;
|
|
|
|
y = new_y ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-07 16:03:53 +01:00
|
|
|
|
2013-07-03 16:39:10 +02:00
|
|
|
/* *** Other operations *** */
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This function computes the intermediate (linear) values between the
|
|
|
|
* current point and the point `end`.
|
|
|
|
*
|
|
|
|
* The number of steps is function of `step_hint` and the distance
|
|
|
|
* between the two points. `step_hint`, as its name indicates, is a hint
|
|
|
|
* of the desired distance between two intermediate coordinates. It is
|
|
|
|
* adjusted by the function to distribute equally the intermediate
|
|
|
|
* coordinates between the two extremities.
|
|
|
|
*
|
|
|
|
* @param[in] end Coordinate of the last extremity.
|
|
|
|
* @param[in,out] step_hint The desired approximate distance between two
|
|
|
|
* intermediate points; when the function returns, it is set to the
|
|
|
|
* actual step used.
|
|
|
|
* @param[out] interpolated The vector in which the intermediate values
|
2014-05-13 01:15:34 +02:00
|
|
|
* will be added. The two extremities are not included in this vector,
|
2013-07-03 16:39:10 +02:00
|
|
|
* but of course the calling function can add values prior and after the
|
2014-05-13 01:15:34 +02:00
|
|
|
* function call (existing data is not erased by this function, only new
|
|
|
|
* points are added at the end of the vector).
|
2013-07-03 16:39:10 +02:00
|
|
|
*/
|
|
|
|
void Point3D::interpolate(const Point3D &end, float &step_hint,
|
|
|
|
std::vector<Point3D> &interpolated) const
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* Example of step computation: if the distance between the two
|
|
|
|
* extremities (`*this` and `end`) is 12.42 m and `step_hint` is set
|
|
|
|
* to 2 m, the number of steps is 12 / 2 == 6, and the actual distance
|
|
|
|
* between two intermediate coordinates is 12.42 / 6 == 2.07 m.
|
|
|
|
*/
|
|
|
|
float dist = distance(end) ;
|
|
|
|
int nb_steps = dist / step_hint ;
|
|
|
|
step_hint = dist / nb_steps ;
|
|
|
|
|
|
|
|
/* Set up the tweener */
|
|
|
|
// Individual tweeners for X, Y and Z
|
|
|
|
double tweened_x = x, tweened_y = y, tweened_z = z ;
|
|
|
|
claw::tween::single_tweener
|
|
|
|
interpolator_x(tweened_x, end.x, dist,
|
|
|
|
claw::tween::easing_linear::ease_in) ;
|
|
|
|
claw::tween::single_tweener
|
|
|
|
interpolator_y(tweened_y, end.y, dist,
|
|
|
|
claw::tween::easing_linear::ease_in) ;
|
|
|
|
claw::tween::single_tweener
|
|
|
|
interpolator_z(tweened_z, end.z, dist,
|
|
|
|
claw::tween::easing_linear::ease_in) ;
|
|
|
|
// Consolidated tweener for both X and Y
|
|
|
|
claw::tween::tweener_group interpolator ;
|
|
|
|
interpolator.insert(interpolator_x) ;
|
|
|
|
interpolator.insert(interpolator_y) ;
|
|
|
|
interpolator.insert(interpolator_z) ;
|
|
|
|
|
|
|
|
/* Compute interpolated values */
|
|
|
|
do
|
|
|
|
{
|
|
|
|
// Update tweened_x, tweened_y, tweened_z
|
|
|
|
interpolator.update(step_hint);
|
|
|
|
// Add the new coordinates to the vector
|
|
|
|
interpolated.push_back(Point3D(tweened_x, tweened_y, tweened_z)) ;
|
|
|
|
}
|
|
|
|
while (! interpolator.is_finished()) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-13 01:15:34 +02:00
|
|
|
/**
|
|
|
|
* This function computes the coordinates of the point that would be
|
|
|
|
* reached by a mobile terminal traveling during `time` at `speed` km/h,
|
|
|
|
* starting from the current point in direction of the point `end`;
|
|
|
|
* these coordinates are returned. In case the speed of the terminal
|
|
|
|
* would allow it to travel further than `end`, `end` is returned.
|
|
|
|
*
|
|
|
|
* @param[in] end Coordinate of the furthest point, in direction of which
|
|
|
|
* the mobile is travelling.
|
|
|
|
* @param[in] speed The maximal speed at which the mobile can travel, in
|
|
|
|
* km/h.
|
|
|
|
* @param[in] duration The travel time of the mobile.
|
|
|
|
*
|
|
|
|
* @returns The coordinates of the furthest point between the current
|
|
|
|
* point and `end` that can be reached by the mobile.
|
|
|
|
* @returns `end` if the mobile could travel further than `end`.
|
|
|
|
*/
|
|
|
|
Point3D Point3D::interpolate(const Point3D &end, const float speed,
|
|
|
|
const Timestamp &duration) const
|
|
|
|
{
|
|
|
|
float dist = distance(end) ; // Distance between the two extremities
|
|
|
|
double speed_mps = speed * 1000 / 3600 ; // Speed in m/s
|
|
|
|
// Duration in seconds:
|
|
|
|
double duration_s = static_cast<uint64_t>(duration) / 1000.0 ;
|
|
|
|
// Distance covered by the mobile during `duration` at `speed`:
|
|
|
|
float dist_covered = speed_mps * duration_s ;
|
|
|
|
|
|
|
|
/* If the mobile is fast enough to reach `end`, return `end` */
|
|
|
|
if (dist_covered >= dist)
|
|
|
|
return end ;
|
|
|
|
|
|
|
|
/* Set up the tweener */
|
|
|
|
// Individual tweeners for X, Y and Z
|
|
|
|
double tweened_x = x, tweened_y = y, tweened_z = z ;
|
|
|
|
claw::tween::single_tweener
|
|
|
|
interpolator_x(tweened_x, end.x, dist,
|
|
|
|
claw::tween::easing_linear::ease_in) ;
|
|
|
|
claw::tween::single_tweener
|
|
|
|
interpolator_y(tweened_y, end.y, dist,
|
|
|
|
claw::tween::easing_linear::ease_in) ;
|
|
|
|
claw::tween::single_tweener
|
|
|
|
interpolator_z(tweened_z, end.z, dist,
|
|
|
|
claw::tween::easing_linear::ease_in) ;
|
|
|
|
// Consolidated tweener for both X and Y
|
|
|
|
claw::tween::tweener_group interpolator ;
|
|
|
|
interpolator.insert(interpolator_x) ;
|
|
|
|
interpolator.insert(interpolator_y) ;
|
|
|
|
interpolator.insert(interpolator_z) ;
|
|
|
|
|
|
|
|
/* Compute the interpolated value */
|
|
|
|
assert(! interpolator.is_finished()) ;
|
|
|
|
// Update tweened_x, tweened_y, tweened_z
|
|
|
|
interpolator.update(dist_covered) ;
|
|
|
|
// Return the interpolated coordinates
|
|
|
|
return Point3D(tweened_x, tweened_y, tweened_z) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-07-03 16:39:10 +02:00
|
|
|
|
2010-01-16 12:23:07 +01:00
|
|
|
/* *** Operators *** */
|
2009-12-07 16:03:53 +01:00
|
|
|
|
|
|
|
|
2011-07-30 20:38:42 +02:00
|
|
|
Point3D& Point3D::operator=(const Point3D &source)
|
2009-12-07 16:03:53 +01:00
|
|
|
{
|
2010-02-03 13:40:27 +01:00
|
|
|
if (this == &source)
|
2009-12-07 16:03:53 +01:00
|
|
|
return *this ;
|
|
|
|
|
2010-02-03 13:40:27 +01:00
|
|
|
x = source.x ;
|
|
|
|
y = source.y ;
|
|
|
|
z = source.z ;
|
2009-12-07 16:03:53 +01:00
|
|
|
|
|
|
|
return *this ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-02-03 13:40:27 +01:00
|
|
|
bool Point3D::operator==(const Point3D &source) const
|
2009-12-07 16:03:53 +01:00
|
|
|
{
|
2010-02-03 13:40:27 +01:00
|
|
|
if (this == &source)
|
2009-12-11 17:56:31 +01:00
|
|
|
return true ;
|
|
|
|
|
2009-12-07 16:03:53 +01:00
|
|
|
return
|
2010-02-03 13:40:27 +01:00
|
|
|
x == source.x &&
|
|
|
|
y == source.y &&
|
|
|
|
z == source.z ;
|
2009-12-07 16:03:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-02-03 13:40:27 +01:00
|
|
|
bool Point3D::operator<(const Point3D &source) const
|
2009-12-07 16:03:53 +01:00
|
|
|
{
|
2010-02-03 13:40:27 +01:00
|
|
|
if (x < source.x)
|
2009-12-07 16:03:53 +01:00
|
|
|
return true ;
|
2010-02-03 13:40:27 +01:00
|
|
|
if (x > source.x)
|
2009-12-07 16:03:53 +01:00
|
|
|
return false ;
|
|
|
|
|
2010-02-03 13:40:27 +01:00
|
|
|
if (y < source.y)
|
2009-12-07 16:03:53 +01:00
|
|
|
return true ;
|
2010-02-03 13:40:27 +01:00
|
|
|
if (y > source.y)
|
2009-12-07 16:03:53 +01:00
|
|
|
return false ;
|
|
|
|
|
2010-02-03 13:40:27 +01:00
|
|
|
if (z < source.z)
|
2009-12-07 16:03:53 +01:00
|
|
|
return true ;
|
|
|
|
|
|
|
|
return false ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-18 13:34:02 +02:00
|
|
|
Point3D::operator std::string(void) const
|
2010-02-04 18:46:23 +01:00
|
|
|
{
|
2011-04-27 18:47:56 +02:00
|
|
|
ostringstream oss ;
|
2010-02-04 18:46:23 +01:00
|
|
|
oss << *this ;
|
|
|
|
return oss.str() ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-05-04 18:16:10 +02:00
|
|
|
/**
|
2013-05-30 21:23:05 +02:00
|
|
|
* @returns `true` if either #x, #y or #z is non-zero.
|
|
|
|
* @returns `false` if #x, #y and #z are defined to 0.
|
2011-05-04 18:16:10 +02:00
|
|
|
*/
|
|
|
|
Point3D::operator bool(void) const
|
|
|
|
{
|
|
|
|
return
|
2012-06-20 17:26:00 +02:00
|
|
|
x != 0 ||
|
|
|
|
y != 0 ||
|
2011-05-04 18:16:10 +02:00
|
|
|
z != 0 ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-07 16:03:53 +01:00
|
|
|
|
2011-04-27 18:47:56 +02:00
|
|
|
ostream& operator<<(ostream &os, const Point3D &p)
|
2009-12-07 16:03:53 +01:00
|
|
|
{
|
|
|
|
os << "(" << p.x << ";" << p.y << ";" << p.z << ")" ;
|
|
|
|
return os ;
|
|
|
|
}
|