123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439 |
- /*
- * Copyright (c) 2008-2018, Andrew Walker
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- #ifdef WIN32
- #define _USE_MATH_DEFINES
- #endif
- #include <math.h>
- #include "dubins.h"
- #define EPSILON (10e-10)
- typedef enum
- {
- L_SEG = 0,
- S_SEG = 1,
- R_SEG = 2
- } SegmentType;
- /* The segment types for each of the Path types */
- const SegmentType DIRDATA[][3] = {
- { L_SEG, S_SEG, L_SEG },
- { L_SEG, S_SEG, R_SEG },
- { R_SEG, S_SEG, L_SEG },
- { R_SEG, S_SEG, R_SEG },
- { R_SEG, L_SEG, R_SEG },
- { L_SEG, R_SEG, L_SEG }
- };
- typedef struct
- {
- double alpha;
- double beta;
- double d;
- double sa;
- double sb;
- double ca;
- double cb;
- double c_ab;
- double d_sq;
- } DubinsIntermediateResults;
- int dubins_word(DubinsIntermediateResults* in, DubinsPathType pathType, double out[3]);
- int dubins_intermediate_results(DubinsIntermediateResults* in, double q0[3], double q1[3], double rho);
- /**
- * Floating point modulus suitable for rings
- *
- * fmod doesn't behave correctly for angular quantities, this function does
- */
- double fmodr( double x, double y)
- {
- return x - y*floor(x/y);
- }
- double mod2pi( double theta )
- {
- return fmodr( theta, 2 * M_PI );
- }
- int dubins_shortest_path(DubinsPath* path, double q0[3], double q1[3], double rho)
- {
- int i, errcode;
- DubinsIntermediateResults in;
- double params[3];
- double cost;
- double best_cost = INFINITY;
- int best_word = -1;
- errcode = dubins_intermediate_results(&in, q0, q1, rho);
- if(errcode != EDUBOK) {
- return errcode;
- }
- path->qi[0] = q0[0];
- path->qi[1] = q0[1];
- path->qi[2] = q0[2];
- path->rho = rho;
- for( i = 0; i < 6; i++ ) {
- DubinsPathType pathType = (DubinsPathType)i;
- errcode = dubins_word(&in, pathType, params);
- if(errcode == EDUBOK) {
- cost = params[0] + params[1] + params[2];
- if(cost < best_cost) {
- best_word = i;
- best_cost = cost;
- path->param[0] = params[0];
- path->param[1] = params[1];
- path->param[2] = params[2];
- path->type = pathType;
- }
- }
- }
- if(best_word == -1) {
- return EDUBNOPATH;
- }
- return EDUBOK;
- }
- int dubins_path(DubinsPath* path, double q0[3], double q1[3], double rho, DubinsPathType pathType)
- {
- int errcode;
- DubinsIntermediateResults in;
- errcode = dubins_intermediate_results(&in, q0, q1, rho);
- if(errcode == EDUBOK) {
- double params[3];
- errcode = dubins_word(&in, pathType, params);
- if(errcode == EDUBOK) {
- path->param[0] = params[0];
- path->param[1] = params[1];
- path->param[2] = params[2];
- path->qi[0] = q0[0];
- path->qi[1] = q0[1];
- path->qi[2] = q0[2];
- path->rho = rho;
- path->type = pathType;
- }
- }
- return errcode;
- }
- double dubins_path_length( DubinsPath* path )
- {
- double length = 0.;
- length += path->param[0];
- length += path->param[1];
- length += path->param[2];
- length = length * path->rho;
- return length;
- }
- double dubins_segment_length( DubinsPath* path, int i )
- {
- if( (i < 0) || (i > 2) )
- {
- return INFINITY;
- }
- return path->param[i] * path->rho;
- }
- double dubins_segment_length_normalized( DubinsPath* path, int i )
- {
- if( (i < 0) || (i > 2) )
- {
- return INFINITY;
- }
- return path->param[i];
- }
- DubinsPathType dubins_path_type( DubinsPath* path )
- {
- return path->type;
- }
- void dubins_segment( double t, double qi[3], double qt[3], SegmentType type)
- {
- double st = sin(qi[2]);
- double ct = cos(qi[2]);
- if( type == L_SEG ) {
- qt[0] = +sin(qi[2]+t) - st;
- qt[1] = -cos(qi[2]+t) + ct;
- qt[2] = t;
- }
- else if( type == R_SEG ) {
- qt[0] = -sin(qi[2]-t) + st;
- qt[1] = +cos(qi[2]-t) - ct;
- qt[2] = -t;
- }
- else if( type == S_SEG ) {
- qt[0] = ct * t;
- qt[1] = st * t;
- qt[2] = 0.0;
- }
- qt[0] += qi[0];
- qt[1] += qi[1];
- qt[2] += qi[2];
- }
- int dubins_path_sample( DubinsPath* path, double t, double q[3] )
- {
- /* tprime is the normalised variant of the parameter t */
- double tprime = t / path->rho;
- double qi[3]; /* The translated initial configuration */
- double q1[3]; /* end-of segment 1 */
- double q2[3]; /* end-of segment 2 */
- const SegmentType* types = DIRDATA[path->type];
- double p1, p2;
- if( t < 0 || t > dubins_path_length(path) ) {
- return EDUBPARAM;
- }
- /* initial configuration */
- qi[0] = 0.0;
- qi[1] = 0.0;
- qi[2] = path->qi[2];
- /* generate the target configuration */
- p1 = path->param[0];
- p2 = path->param[1];
- dubins_segment( p1, qi, q1, types[0] );
- dubins_segment( p2, q1, q2, types[1] );
- if( tprime < p1 ) {
- dubins_segment( tprime, qi, q, types[0] );
- }
- else if( tprime < (p1+p2) ) {
- dubins_segment( tprime-p1, q1, q, types[1] );
- }
- else {
- dubins_segment( tprime-p1-p2, q2, q, types[2] );
- }
- /* scale the target configuration, translate back to the original starting point */
- q[0] = q[0] * path->rho + path->qi[0];
- q[1] = q[1] * path->rho + path->qi[1];
- q[2] = mod2pi(q[2]);
- return EDUBOK;
- }
- int dubins_path_sample_many(DubinsPath* path, double stepSize,
- DubinsPathSamplingCallback cb, void* user_data)
- {
- int retcode;
- double q[3];
- double x = 0.0;
- double length = dubins_path_length(path);
- while( x < length ) {
- dubins_path_sample( path, x, q );
- retcode = cb(q, x, user_data);
- if( retcode != 0 ) {
- return retcode;
- }
- x += stepSize;
- }
- return 0;
- }
- int dubins_path_endpoint( DubinsPath* path, double q[3] )
- {
- return dubins_path_sample( path, dubins_path_length(path) - EPSILON, q );
- }
- int dubins_extract_subpath( DubinsPath* path, double t, DubinsPath* newpath )
- {
- /* calculate the true parameter */
- double tprime = t / path->rho;
- if((t < 0) || (t > dubins_path_length(path)))
- {
- return EDUBPARAM;
- }
- /* copy most of the data */
- newpath->qi[0] = path->qi[0];
- newpath->qi[1] = path->qi[1];
- newpath->qi[2] = path->qi[2];
- newpath->rho = path->rho;
- newpath->type = path->type;
- /* fix the parameters */
- newpath->param[0] = fmin( path->param[0], tprime );
- newpath->param[1] = fmin( path->param[1], tprime - newpath->param[0]);
- newpath->param[2] = fmin( path->param[2], tprime - newpath->param[0] - newpath->param[1]);
- return 0;
- }
- int dubins_intermediate_results(DubinsIntermediateResults* in, double q0[3], double q1[3], double rho)
- {
- double dx, dy, D, d, theta, alpha, beta;
- if( rho <= 0.0 ) {
- return EDUBBADRHO;
- }
- dx = q1[0] - q0[0];
- dy = q1[1] - q0[1];
- D = sqrt( dx * dx + dy * dy );
- d = D / rho;
- theta = 0;
- /* test required to prevent domain errors if dx=0 and dy=0 */
- if(d > 0) {
- theta = mod2pi(atan2( dy, dx ));
- }
- alpha = mod2pi(q0[2] - theta);
- beta = mod2pi(q1[2] - theta);
- in->alpha = alpha;
- in->beta = beta;
- in->d = d;
- in->sa = sin(alpha);
- in->sb = sin(beta);
- in->ca = cos(alpha);
- in->cb = cos(beta);
- in->c_ab = cos(alpha - beta);
- in->d_sq = d * d;
- return EDUBOK;
- }
- int dubins_LSL(DubinsIntermediateResults* in, double out[3])
- {
- double tmp0, tmp1, p_sq;
- tmp0 = in->d + in->sa - in->sb;
- p_sq = 2 + in->d_sq - (2*in->c_ab) + (2 * in->d * (in->sa - in->sb));
- if(p_sq >= 0) {
- tmp1 = atan2( (in->cb - in->ca), tmp0 );
- out[0] = mod2pi(tmp1 - in->alpha);
- out[1] = sqrt(p_sq);
- out[2] = mod2pi(in->beta - tmp1);
- return EDUBOK;
- }
- return EDUBNOPATH;
- }
- int dubins_RSR(DubinsIntermediateResults* in, double out[3])
- {
- double tmp0 = in->d - in->sa + in->sb;
- double p_sq = 2 + in->d_sq - (2 * in->c_ab) + (2 * in->d * (in->sb - in->sa));
- if( p_sq >= 0 ) {
- double tmp1 = atan2( (in->ca - in->cb), tmp0 );
- out[0] = mod2pi(in->alpha - tmp1);
- out[1] = sqrt(p_sq);
- out[2] = mod2pi(tmp1 -in->beta);
- return EDUBOK;
- }
- return EDUBNOPATH;
- }
- int dubins_LSR(DubinsIntermediateResults* in, double out[3])
- {
- double p_sq = -2 + (in->d_sq) + (2 * in->c_ab) + (2 * in->d * (in->sa + in->sb));
- if( p_sq >= 0 ) {
- double p = sqrt(p_sq);
- double tmp0 = atan2( (-in->ca - in->cb), (in->d + in->sa + in->sb) ) - atan2(-2.0, p);
- out[0] = mod2pi(tmp0 - in->alpha);
- out[1] = p;
- out[2] = mod2pi(tmp0 - mod2pi(in->beta));
- return EDUBOK;
- }
- return EDUBNOPATH;
- }
- int dubins_RSL(DubinsIntermediateResults* in, double out[3])
- {
- double p_sq = -2 + in->d_sq + (2 * in->c_ab) - (2 * in->d * (in->sa + in->sb));
- if( p_sq >= 0 ) {
- double p = sqrt(p_sq);
- double tmp0 = atan2( (in->ca + in->cb), (in->d - in->sa - in->sb) ) - atan2(2.0, p);
- out[0] = mod2pi(in->alpha - tmp0);
- out[1] = p;
- out[2] = mod2pi(in->beta - tmp0);
- return EDUBOK;
- }
- return EDUBNOPATH;
- }
- int dubins_RLR(DubinsIntermediateResults* in, double out[3])
- {
- double tmp0 = (6. - in->d_sq + 2*in->c_ab + 2*in->d*(in->sa - in->sb)) / 8.;
- double phi = atan2( in->ca - in->cb, in->d - in->sa + in->sb );
- if( fabs(tmp0) <= 1) {
- double p = mod2pi((2*M_PI) - acos(tmp0) );
- double t = mod2pi(in->alpha - phi + mod2pi(p/2.));
- out[0] = t;
- out[1] = p;
- out[2] = mod2pi(in->alpha - in->beta - t + mod2pi(p));
- return EDUBOK;
- }
- return EDUBNOPATH;
- }
- int dubins_LRL(DubinsIntermediateResults* in, double out[3])
- {
- double tmp0 = (6. - in->d_sq + 2*in->c_ab + 2*in->d*(in->sb - in->sa)) / 8.;
- double phi = atan2( in->ca - in->cb, in->d + in->sa - in->sb );
- if( fabs(tmp0) <= 1) {
- double p = mod2pi( 2*M_PI - acos( tmp0) );
- double t = mod2pi(-in->alpha - phi + p/2.);
- out[0] = t;
- out[1] = p;
- out[2] = mod2pi(mod2pi(in->beta) - in->alpha -t + mod2pi(p));
- return EDUBOK;
- }
- return EDUBNOPATH;
- }
- int dubins_word(DubinsIntermediateResults* in, DubinsPathType pathType, double out[3])
- {
- int result;
- switch(pathType)
- {
- case LSL:
- result = dubins_LSL(in, out);
- break;
- case RSL:
- result = dubins_RSL(in, out);
- break;
- case LSR:
- result = dubins_LSR(in, out);
- break;
- case RSR:
- result = dubins_RSR(in, out);
- break;
- case LRL:
- result = dubins_LRL(in, out);
- break;
- case RLR:
- result = dubins_RLR(in, out);
- break;
- default:
- result = EDUBNOPATH;
- }
- return result;
- }
|