Main Page   Namespace List   Class Hierarchy   Compound List   File List   Compound Members   File Members  

Geometry.cpp

Go to the documentation of this file.
00001 /*
00002 Copyright (c) 2000-2003, Jelle Kok, University of Amsterdam
00003 All rights reserved.
00004 
00005 Redistribution and use in source and binary forms, with or without
00006 modification, are permitted provided that the following conditions are met:
00007 
00008 1. Redistributions of source code must retain the above copyright notice, this
00009 list of conditions and the following disclaimer.
00010 
00011 2. Redistributions in binary form must reproduce the above copyright notice,
00012 this list of conditions and the following disclaimer in the documentation
00013 and/or other materials provided with the distribution.
00014 
00015 3. Neither the name of the University of Amsterdam nor the names of its
00016 contributors may be used to endorse or promote products derived from this
00017 software without specific prior written permission.
00018 
00019 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00020 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00021 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
00023 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00024 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00025 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00026 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00027 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00028 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029 */
00030 
00055 #include "Geometry.h"
00056 #include <stdio.h>    // needed for sprintf
00057 
00062 int sign( double d1 )
00063 {
00064   return (d1>0)?1:-1;
00065 }
00066 
00071 double max( double d1, double d2 )
00072 {
00073   return (d1>d2)?d1:d2;
00074 }
00075 
00080 double min( double d1, double d2 )
00081 {
00082   return (d1<d2)?d1:d2;
00083 }
00084 
00085 
00090 AngDeg Rad2Deg( AngRad x )
00091 {
00092   return ( x * 180 / M_PI );
00093 }
00094 
00099 AngRad Deg2Rad( AngDeg x )
00100 {
00101   return ( x * M_PI / 180 );
00102 }
00103 
00108 double cosDeg( AngDeg x )
00109 {
00110   return ( cos( Deg2Rad( x ) ) );
00111 }
00112 
00117 double sinDeg( AngDeg x )
00118 {
00119   return ( sin( Deg2Rad( x ) ) );
00120 }
00121 
00126 double tanDeg( AngDeg x )
00127 {
00128   return ( tan( Deg2Rad( x ) ) );
00129 }
00130 
00136 AngDeg atanDeg( double x )
00137 {
00138   return ( Rad2Deg( atan( x ) ) );
00139 }
00140 
00149 double atan2Deg( double x, double y )
00150 {
00151   if( fabs( x ) < EPSILON && fabs( y ) < EPSILON )
00152     return ( 0.0 );
00153 
00154   return ( Rad2Deg( atan2( x, y ) ) );
00155 }
00156 
00161 AngDeg acosDeg( double x )
00162 {
00163   if( x >= 1 )
00164     return ( 0.0 );
00165   else if( x <= -1 )
00166     return ( 180.0 );
00167 
00168   return ( Rad2Deg( acos( x ) ) );
00169 }
00170 
00175 AngDeg asinDeg( double x )
00176 {
00177   if( x >= 1 )
00178     return ( 90.0 );
00179   else if ( x <= -1 )
00180     return ( -90.0 );
00181 
00182   return ( Rad2Deg( asin( x ) ) );
00183 }
00184 
00193 bool isAngInInterval( AngDeg ang, AngDeg angMin, AngDeg angMax )
00194 {
00195   // convert all angles to interval 0..360
00196   if( ( ang    + 360 ) < 360 ) ang    += 360;
00197   if( ( angMin + 360 ) < 360 ) angMin += 360;
00198   if( ( angMax + 360 ) < 360 ) angMax += 360;
00199 
00200   if( angMin < angMax ) // 0 ---false-- angMin ---true-----angMax---false--360
00201     return angMin < ang && ang < angMax ;
00202   else                  // 0 ---true--- angMax ---false----angMin---true---360
00203     return !( angMax < ang && ang < angMin );
00204 }
00205 
00212 AngDeg getBisectorTwoAngles( AngDeg angMin, AngDeg angMax )
00213 {
00214   // separate sine and cosine part to circumvent boundary problem
00215   return VecPosition::normalizeAngle(
00216             atan2Deg( (sinDeg( angMin) + sinDeg( angMax ) )/2.0,
00217                       (cosDeg( angMin) + cosDeg( angMax ) )/2.0 ) );
00218 }
00219 
00220 /*****************************************************************************/
00221 /*******************   CLASS VECPOSITION   ***********************************/
00222 /*****************************************************************************/
00223 
00238 VecPosition::VecPosition( double x, double y, CoordSystemT cs )
00239 {
00240   setVecPosition( x, y, cs );
00241 }
00242 
00247 VecPosition VecPosition::operator - ( )
00248 {
00249   return ( VecPosition( -m_x, -m_y ) );
00250 }
00251 
00260 VecPosition VecPosition::operator + ( const double &d )
00261 {
00262   return ( VecPosition( m_x + d, m_y + d ) );
00263 }
00264 
00270 VecPosition VecPosition::operator + ( const VecPosition &p )
00271 {
00272   return ( VecPosition( m_x + p.m_x, m_y + p.m_y ) );
00273 }
00274 
00283 VecPosition VecPosition::operator - ( const double &d )
00284 {
00285   return ( VecPosition( m_x - d, m_y - d ) );
00286 }
00287 
00296 VecPosition VecPosition::operator - ( const VecPosition &p )
00297 {
00298   return ( VecPosition( m_x - p.m_x, m_y - p.m_y ) );
00299 }
00300 
00308 VecPosition VecPosition::operator * ( const double &d  )
00309 {
00310   return ( VecPosition( m_x * d, m_y * d  ) );
00311 }
00312 
00320 VecPosition VecPosition::operator * ( const VecPosition &p )
00321 {
00322   return ( VecPosition( m_x * p.m_x, m_y * p.m_y ) );
00323 }
00324 
00333 VecPosition VecPosition::operator / ( const double &d )
00334 {
00335   return ( VecPosition( m_x / d, m_y / d  ) );
00336 }
00337 
00345 VecPosition VecPosition::operator / ( const VecPosition &p )
00346 {
00347   return ( VecPosition( m_x / p.m_x, m_y / p.m_y ) );
00348 }
00349 
00355 void VecPosition::operator = ( const double &d )
00356 {
00357   m_x = d;
00358   m_y = d;
00359 }
00360 
00366 void VecPosition::operator +=( const VecPosition &p )
00367 {
00368   m_x += p.m_x;
00369   m_y += p.m_y;
00370 }
00371 
00378 void VecPosition::operator += ( const double &d )
00379 {
00380   m_x += d;
00381   m_y += d;
00382 }
00383 
00391 void VecPosition::operator -=( const VecPosition &p )
00392 {
00393   m_x -= p.m_x;
00394   m_y -= p.m_y;
00395 }
00396 
00404 void VecPosition::operator -=( const double &d )
00405 {
00406   m_x -= d;
00407   m_y -= d;
00408 }
00409 
00417 void VecPosition::operator *=( const VecPosition &p )
00418 {
00419   m_x *= p.m_x;
00420   m_y *= p.m_y;
00421 }
00422 
00430 void VecPosition::operator *=( const double &d )
00431 {
00432   m_x *= d;
00433   m_y *= d;
00434 }
00435 
00442 void VecPosition::operator /=( const VecPosition &p )
00443 {
00444   m_x /= p.m_x;
00445   m_y /= p.m_y;
00446 }
00447 
00455 void VecPosition::operator /=( const double &d )
00456 {
00457   m_x /= d;
00458   m_y /= d;
00459 }
00460 
00468 bool VecPosition::operator !=( const VecPosition &p )
00469 {
00470   return ( ( m_x != p.m_x ) || ( m_y != p.m_y ) );
00471 }
00472 
00482 bool VecPosition::operator !=( const double &d )
00483 {
00484   return ( ( m_x != d ) || ( m_y != d ) );
00485 }
00486 
00495 bool VecPosition::operator ==( const VecPosition &p )
00496 {
00497   return ( ( m_x == p.m_x ) && ( m_y == p.m_y ) );
00498 }
00499 
00509 bool VecPosition::operator ==( const double &d )
00510 {
00511   return ( ( m_x == d ) && ( m_y == d ) );
00512 }
00513 
00522 ostream& operator <<( ostream &os, VecPosition v )
00523 {
00524   return ( os << "( " << v.m_x << ", " << v.m_y << " )" );
00525 }
00526 
00532 void VecPosition::show( CoordSystemT cs )
00533 {
00534   if( cs == CARTESIAN )
00535     cout << *this << endl;
00536   else
00537     cout << "( r: " << getMagnitude( ) << ", phi: " << getDirection( ) << "  )";
00538 }
00539 
00547 string VecPosition::str( CoordSystemT cs )
00548 {
00549   char buf[ 1024 ];
00550 
00551   if( cs == CARTESIAN )
00552     sprintf( buf, "( %f, %f )", getX( ), getY( ) );
00553   else
00554     sprintf( buf, "( r: %f, phi: %f )", getMagnitude( ), getDirection( ) );
00555 
00556   string str( buf );
00557   return ( str );
00558 }
00559 
00564 bool VecPosition::setX( double dX )
00565 {
00566   m_x = dX;
00567   return ( true );
00568 }
00569 
00573 double VecPosition::getX( ) const
00574 {
00575   return ( m_x );
00576 }
00577 
00582 bool VecPosition::setY( double dY )
00583 {
00584   m_y = dY;
00585   return ( true );
00586 }
00587 
00591 double VecPosition::getY( ) const
00592 {
00593   return ( m_y );
00594 }
00595 
00611 void VecPosition::setVecPosition( double dX, double dY, CoordSystemT cs)
00612 {
00613   if( cs == CARTESIAN )
00614   {
00615     m_x = dX;
00616     m_y = dY;
00617   }
00618   else
00619     *this = getVecPositionFromPolar( dX, dY );
00620 }
00621 
00630 double VecPosition::getDistanceTo( const VecPosition p )
00631 {
00632   return ( ( *this - p ).getMagnitude( ) );
00633 }
00634 
00647 VecPosition VecPosition::setMagnitude( double d )
00648 {
00649   if( getMagnitude( ) > EPSILON )
00650      ( *this ) *= ( d / getMagnitude( ) );
00651 
00652   return ( *this );
00653 }
00654 
00661 double VecPosition::getMagnitude( ) const
00662 {
00663   return ( sqrt( m_x * m_x + m_y * m_y ) );
00664 }
00665 
00674 AngDeg VecPosition::getDirection( ) const
00675 {
00676   return ( atan2Deg( m_y, m_x ) );
00677 }
00678 
00687 bool VecPosition::isInFrontOf( const VecPosition &p )
00688 {
00689   return ( ( m_x > p.getX( ) ) ? true : false );
00690 }
00691 
00701 bool VecPosition::isInFrontOf( const double &d )
00702 {
00703   return ( ( m_x > d ) ? true : false );
00704 }
00705 
00716 bool VecPosition::isBehindOf( const VecPosition &p )
00717 {
00718   return ( ( m_x < p.getX( ) ) ? true : false );
00719 }
00720 
00729 bool VecPosition::isBehindOf( const double &d )
00730 {
00731   return ( ( m_x < d ) ? true : false );
00732 }
00733 
00744 bool VecPosition::isLeftOf( const VecPosition &p )
00745 {
00746   return ( ( m_y < p.getY( ) ) ? true : false );
00747 }
00748 
00758 bool VecPosition::isLeftOf( const double &d )
00759 {
00760   return ( ( m_y < d ) ? true : false );
00761 }
00762 
00773 bool VecPosition::isRightOf( const VecPosition &p )
00774 {
00775   return ( ( m_y > p.getY( ) ) ? true : false );
00776 }
00777 
00787 bool VecPosition::isRightOf( const double &d )
00788 {
00789   return ( ( m_y > d ) ? true : false );
00790 }
00791 
00806 bool VecPosition::isBetweenX( const VecPosition &p1, const VecPosition &p2 )
00807 {
00808   return ( ( isInFrontOf( p1 ) && isBehindOf( p2 ) ) ? true : false );
00809 }
00810 
00824 bool VecPosition::isBetweenX( const double &d1, const double &d2 )
00825 {
00826   return ( ( isInFrontOf( d1 ) && isBehindOf( d2 ) ) ? true : false );
00827 }
00828 
00843 bool VecPosition::isBetweenY( const VecPosition &p1, const VecPosition &p2 )
00844 {
00845   return ( ( isRightOf( p1 ) && isLeftOf( p2 ) ) ? true : false );
00846 }
00847 
00861 bool VecPosition::isBetweenY( const double &d1, const double &d2 )
00862 {
00863   return ( ( isRightOf( d1 ) && isLeftOf( d2 ) ) ? true : false );
00864 }
00865 
00872 VecPosition VecPosition::normalize( )
00873 {
00874   return ( setMagnitude( 1.0 ) );
00875 }
00876 
00891 VecPosition VecPosition::rotate( AngDeg angle )
00892 {
00893   // determine the polar representation of the current VecPosition
00894   double dMag    = this->getMagnitude( );
00895   double dNewDir = this->getDirection( ) + angle;  // add rotation angle to phi
00896   setVecPosition( dMag, dNewDir, POLAR );          // convert back to Cartesian
00897   return ( *this );
00898 }
00899 
00917 VecPosition VecPosition::globalToRelative( VecPosition origin, AngDeg ang )
00918 {
00919   // convert global coordinates into relative coordinates by aligning
00920   // relative frame and world frame. First perform translation to make
00921   // origins of both frames coincide. Then perform rotation to make
00922   // axes of both frames coincide (use negative angle since you rotate
00923   // relative frame to world frame).
00924   *this -= origin;
00925   return ( rotate( -ang ) );
00926 }
00927 
00943 VecPosition VecPosition::relativeToGlobal( VecPosition origin, AngDeg ang )
00944 {
00945   // convert relative coordinates into global coordinates by aligning
00946   // world frame and relative frame. First perform rotation to make
00947   // axes of both frames coincide (use positive angle since you rotate
00948   // world frame to relative frame). Then perform translation to make
00949   // origins of both frames coincide.
00950   rotate( ang );
00951   *this += origin;
00952   return ( *this );
00953 }
00954 
00969 VecPosition VecPosition::getVecPositionOnLineFraction( VecPosition &p,
00970                                                        double      dFrac )
00971 {
00972   // determine point on line that lies at fraction dFrac of whole line
00973   // example: this --- 0.25 ---------  p
00974   // formula: this + dFrac * ( p - this ) = this - dFrac * this + dFrac * p =
00975   //          ( 1 - dFrac ) * this + dFrac * p
00976   return ( ( *this ) * ( 1.0 - dFrac ) + ( p * dFrac ) );
00977 }
00978 
00991 VecPosition VecPosition::getVecPositionFromPolar( double dMag, AngDeg ang )
00992 {
00993   // cos(phi) = x/r <=> x = r*cos(phi); sin(phi) = y/r <=> y = r*sin(phi)
00994   return ( VecPosition( dMag * cosDeg( ang ), dMag * sinDeg( ang ) ) );
00995 }
00996 
01003 AngDeg VecPosition::normalizeAngle( AngDeg angle )
01004 {
01005   while( angle > 180.0  ) angle -= 360.0;
01006   while( angle < -180.0 ) angle += 360.0;
01007 
01008   return ( angle );
01009 }
01010 
01011 
01012 /*****************************************************************************/
01013 /********************** CLASS GEOMETRY ***************************************/
01014 /*****************************************************************************/
01015 
01026 double Geometry::getLengthGeomSeries( double dFirst, double dRatio, double dSum )
01027 {
01028   if( dRatio < 0 )
01029     cerr << "(Geometry:getLengthGeomSeries): negative ratio" << endl;
01030 
01031   // s = a + ar + ar^2 + .. + ar^n-1 and thus sr = ar + ar^2 + .. + ar^n
01032   // subtract: sr - s = - a + ar^n) =>  s(1-r)/a + 1 = r^n = temp
01033   // log r^n / n = n log r / log r = n = length
01034   double temp = (dSum * ( dRatio - 1 ) / dFirst) + 1;
01035   if( temp <= 0 )
01036     return -1.0;
01037   return log( temp ) / log( dRatio ) ;
01038 }
01039 
01050 double Geometry::getSumGeomSeries( double dFirst, double dRatio, double dLength)
01051 {
01052   // s = a + ar + ar^2 + .. + ar^n-1 and thus sr = ar + ar^2 + .. + ar^n
01053   // subtract: s - sr = a - ar^n) =>  s = a(1-r^n)/(1-r)
01054   return dFirst * ( 1 - pow( dRatio, dLength ) ) / ( 1 - dRatio ) ;
01055 }
01056 
01067 double Geometry::getSumInfGeomSeries( double dFirst, double dRatio )
01068 {
01069   if( dRatio > 1 )
01070     cerr << "(Geometry:CalcLengthGeomSeries): series does not converge" <<endl;
01071 
01072   // s = a(1-r^n)/(1-r) with n->inf and 0<r<1 => r^n = 0
01073   return dFirst / ( 1 - dRatio );
01074 }
01075 
01086 double Geometry::getFirstGeomSeries( double dSum, double dRatio, double dLength)
01087 {
01088   // s = a + ar + ar^2 + .. + ar^n-1 and thus sr = ar + ar^2 + .. + ar^n
01089   // subtract: s - sr = a - ar^n) =>  s = a(1-r^n)/(1-r) => a = s*(1-r)/(1-r^n)
01090   return dSum *  ( 1 - dRatio )/( 1 - pow( dRatio, dLength ) ) ;
01091 }
01092 
01103 double Geometry::getFirstInfGeomSeries( double dSum, double dRatio )
01104 {
01105   if( dRatio > 1 )
01106     cerr << "(Geometry:getFirstInfGeomSeries):series does not converge" <<endl;
01107 
01108   // s = a(1-r^n)/(1-r) with r->inf and 0<r<1 => r^n = 0 => a = s ( 1 - r)
01109   return dSum * ( 1 - dRatio );
01110 }
01111 
01121 int Geometry::abcFormula(double a, double b, double c, double *s1, double *s2)
01122 {
01123   double dDiscr = b*b - 4*a*c;       // discriminant is b^2 - 4*a*c
01124   if (fabs(dDiscr) < EPSILON )       // if discriminant = 0
01125   {
01126     *s1 = -b / (2 * a);              //  only one solution
01127     return 1;
01128   }
01129   else if (dDiscr < 0)               // if discriminant < 0
01130     return 0;                        //  no solutions
01131   else                               // if discriminant > 0
01132   {
01133     dDiscr = sqrt(dDiscr);           //  two solutions
01134     *s1 = (-b + dDiscr ) / (2 * a);
01135     *s2 = (-b - dDiscr ) / (2 * a);
01136     return 2;
01137   }
01138 }
01139 
01140 /*****************************************************************************/
01141 /********************* CLASS CIRCLE ******************************************/
01142 /*****************************************************************************/
01143 
01148 Circle::Circle( VecPosition pos, double dR )
01149 {
01150   setCircle( pos, dR );
01151 }
01152 
01155 Circle::Circle( )
01156 {
01157   setCircle( VecPosition(-1000.0,-1000.0), 0);
01158 }
01159 
01164 void Circle::show( ostream& os)
01165 {
01166   os << "c:" << m_posCenter << ", r:" << m_dRadius;
01167 }
01168 
01174 bool Circle::setCircle( VecPosition pos, double dR )
01175 {
01176   setCenter( pos );
01177   return setRadius( dR  );
01178 }
01182 bool Circle::setRadius( double dR )
01183 {
01184   if( dR > 0 )
01185   {
01186     m_dRadius = dR;
01187     return true;
01188   }
01189   else
01190   {
01191     m_dRadius = 0.0;
01192     return false;
01193   }
01194 }
01195 
01198 double Circle::getRadius()
01199 {
01200   return m_dRadius;
01201 }
01202 
01206 bool Circle::setCenter( VecPosition pos )
01207 {
01208   m_posCenter = pos;
01209   return true;
01210 }
01211 
01214 VecPosition Circle::getCenter()
01215 {
01216   return m_posCenter;
01217 }
01218 
01221 double Circle::getCircumference()
01222 {
01223   return 2.0*M_PI*getRadius();
01224 }
01225 
01228 double Circle::getArea()
01229 {
01230   return M_PI*getRadius()*getRadius();
01231 }
01232 
01240 bool Circle::isInside( VecPosition pos )
01241 {
01242   return m_posCenter.getDistanceTo( pos ) < getRadius() ;
01243 }
01244 
01251 int Circle::getIntersectionPoints( Circle c, VecPosition *p1, VecPosition *p2)
01252 {
01253     double x0, y0, r0;
01254     double x1, y1, r1;
01255 
01256     x0 = getCenter( ).getX();
01257     y0 = getCenter( ).getY();
01258     r0 = getRadius( );
01259     x1 = c.getCenter( ).getX();
01260     y1 = c.getCenter( ).getY();
01261     r1 = c.getRadius( );
01262 
01263     double      d, dx, dy, h, a, x, y, p2_x, p2_y;
01264 
01265     // first calculate distance between two centers circles P0 and P1.
01266     dx = x1 - x0;
01267     dy = y1 - y0;
01268     d = sqrt(dx*dx + dy*dy);
01269 
01270     // normalize differences
01271     dx /= d; dy /= d;
01272 
01273     // a is distance between p0 and point that is the intersection point P2
01274     // that intersects P0-P1 and the line that crosses the two intersection
01275     // points P3 and P4.
01276     // Define two triangles: P0,P2,P3 and P1,P2,P3.
01277     // with distances a, h, r0 and b, h, r1 with d = a + b
01278     // We know a^2 + h^2 = r0^2 and b^2 + h^2 = r1^2 which then gives
01279     // a^2 + r1^2 - b^2 = r0^2 with d = a + b ==> a^2 + r1^2 - (d-a)^2 = r0^2
01280     // ==> r0^2 + d^2 - r1^2 / 2*d
01281     a = (r0*r0 + d*d - r1*r1) / (2.0 * d);
01282 
01283     // h is then a^2 + h^2 = r0^2 ==> h = sqrt( r0^2 - a^2 )
01284     double      arg = r0*r0 - a*a;
01285     h = (arg > 0.0) ? sqrt(arg) : 0.0;
01286 
01287     // First calculate P2
01288     p2_x = x0 + a * dx;
01289     p2_y = y0 + a * dy;
01290 
01291     // and finally the two intersection points
01292     x =  p2_x - h * dy;
01293     y =  p2_y + h * dx;
01294     p1->setVecPosition( x, y );
01295     x =  p2_x + h * dy;
01296     y =  p2_y - h * dx;
01297     p2->setVecPosition( x, y );
01298 
01299     return (arg < 0.0) ? 0 : ((arg == 0.0 ) ? 1 :  2);
01300 }
01301 
01305 double Circle::getIntersectionArea( Circle c )
01306 {
01307   VecPosition pos1, pos2, pos3;
01308   double d, h, dArea;
01309   AngDeg ang;
01310 
01311   d = getCenter().getDistanceTo( c.getCenter() ); // dist between two centers
01312   if( d > c.getRadius() + getRadius() )           // larger than sum radii
01313     return 0.0;                                   // circles do not intersect
01314   if( d <= fabs(c.getRadius() - getRadius() ) )   // one totally in the other
01315   {
01316     double dR = min( c.getRadius(), getRadius() );// return area smallest circ
01317     return M_PI*dR*dR;
01318   }
01319 
01320   int iNrSol = getIntersectionPoints( c, &pos1, &pos2 );
01321   if( iNrSol != 2 )
01322     return 0.0;
01323 
01324   // the intersection area of two circles can be divided into two segments:
01325   // left and right of the line between the two intersection points p1 and p2.
01326   // The outside area of each segment can be calculated by taking the part
01327   // of the circle pie excluding the triangle from the center to the
01328   // two intersection points.
01329   // The pie equals pi*r^2 * rad(2*ang) / 2*pi = 0.5*rad(2*ang)*r^2 with ang
01330   // the angle between the center c of the circle and one of the two
01331   // intersection points. Thus the angle between c and p1 and c and p3 where
01332   // p3 is the point that lies halfway between p1 and p2.
01333   // This can be calculated using ang = asin( d / r ) with d the distance
01334   // between p1 and p3 and r the radius of the circle.
01335   // The area of the triangle is 2*0.5*h*d.
01336 
01337   pos3 = pos1.getVecPositionOnLineFraction( pos2, 0.5 );
01338   d = pos1.getDistanceTo( pos3 );
01339   h = pos3.getDistanceTo( getCenter() );
01340   ang = asin( d / getRadius() );
01341 
01342   dArea = ang*getRadius()*getRadius();
01343   dArea = dArea - d*h;
01344 
01345   // and now for the other segment the same story
01346   h = pos3.getDistanceTo( c.getCenter() );
01347   ang = asin( d / c.getRadius() );
01348   dArea = dArea + ang*c.getRadius()*c.getRadius();
01349   dArea = dArea - d*h;
01350 
01351   return dArea;
01352 }
01353 
01354 
01355 /*****************************************************************************/
01356 /***********************  CLASS LINE *****************************************/
01357 /*****************************************************************************/
01358 
01364 Line::Line( double dA, double dB, double dC )
01365 {
01366   m_a = dA;
01367   m_b = dB;
01368   m_c = dC;
01369 }
01370 
01376 ostream& operator <<(ostream & os, Line l)
01377 {
01378   double a = l.getACoefficient();
01379   double b = l.getBCoefficient();
01380   double c = l.getCCoefficient();
01381 
01382   // ay + bx + c = 0 -> y = -b/a x - c/a
01383   if( a == 0 )
01384     os << "x = " << -c/b;
01385   else
01386   {
01387     os << "y = ";
01388     if( b != 0 )
01389       os << -b/a << "x ";
01390     if( c > 0 )
01391        os << "- " <<  fabs(c/a);
01392     else if( c < 0 )
01393        os << "+ " <<  fabs(c/a);
01394   }
01395   return os;
01396 }
01397 
01400 void Line::show( ostream& os)
01401 {
01402   os << *this;
01403 }
01404 
01409 VecPosition Line::getIntersection( Line line )
01410 {
01411   VecPosition pos;
01412   double x, y;
01413   if( ( m_a / m_b ) ==  (line.getACoefficient() / line.getBCoefficient() ))
01414     return pos; // lines are parallel, no intersection
01415   if( m_a == 0 )            // bx + c = 0 and a2*y + b2*x + c2 = 0 ==> x = -c/b
01416   {                          // calculate x using the current line
01417     x = -m_c/m_b;                // and calculate the y using the second line
01418     y = line.getYGivenX(x);
01419   }
01420   else if( line.getACoefficient() == 0 )
01421   {                         // ay + bx + c = 0 and b2*x + c2 = 0 ==> x = -c2/b2
01422    x = -line.getCCoefficient()/line.getBCoefficient(); // calculate x using
01423    y = getYGivenX(x);       // 2nd line and calculate y using current line
01424   }
01425   // ay + bx + c = 0 and a2y + b2*x + c2 = 0
01426   // y = (-b2/a2)x - c2/a2
01427   // bx = -a*y - c =>  bx = -a*(-b2/a2)x -a*(-c2/a2) - c ==>
01428   // ==> a2*bx = a*b2*x + a*c2 - a2*c ==> x = (a*c2 - a2*c)/(a2*b - a*b2)
01429   // calculate x using the above formula and the y using the current line
01430   else
01431   {
01432     x = (m_a*line.getCCoefficient() - line.getACoefficient()*m_c)/
01433                     (line.getACoefficient()*m_b - m_a*line.getBCoefficient());
01434     y = getYGivenX(x);
01435   }
01436 
01437   return VecPosition( x, y );
01438 }
01439 
01440 
01448 int Line::getCircleIntersectionPoints( Circle circle,
01449               VecPosition *posSolution1, VecPosition *posSolution2 )
01450 {
01451   int    iSol;
01452   double dSol1=0, dSol2=0;
01453   double h = circle.getCenter().getX();
01454   double k = circle.getCenter().getY();
01455 
01456   // line:   x = -c/b (if a = 0)
01457   // circle: (x-h)^2 + (y-k)^2 = r^2, with h = center.x and k = center.y
01458   // fill in:(-c/b-h)^2 + y^2 -2ky + k^2 - r^2 = 0
01459   //         y^2 -2ky + (-c/b-h)^2 + k^2 - r^2 = 0
01460   // and determine solutions for y using abc-formula
01461   if( fabs(m_a) < EPSILON )
01462   {
01463     iSol = Geometry::abcFormula( 1, -2*k, ((-m_c/m_b) - h)*((-m_c/m_b) - h)
01464               + k*k - circle.getRadius()*circle.getRadius(), &dSol1, &dSol2);
01465     posSolution1->setVecPosition( (-m_c/m_b), dSol1 );
01466     posSolution2->setVecPosition( (-m_c/m_b), dSol2 );
01467     return iSol;
01468   }
01469 
01470   // ay + bx + c = 0 => y = -b/a x - c/a, with da = -b/a and db = -c/a
01471   // circle: (x-h)^2 + (y-k)^2 = r^2, with h = center.x and k = center.y
01472   // fill in:x^2 -2hx + h^2 + (da*x-db)^2 -2k(da*x-db) + k^2 - r^2 = 0
01473   //         x^2 -2hx + h^2 + da^2*x^2 + 2da*db*x + db^2 -2k*da*x -2k*db
01474   //                                                         + k^2 - r^2 = 0
01475   //       (1+da^2)*x^2 + 2(da*db-h-k*da)*x + h2 + db^2  -2k*db + k^2 - r^2 = 0
01476   // and determine solutions for x using abc-formula
01477   // fill in x in original line equation to get y coordinate
01478   double da = -m_b/m_a;
01479   double db = -m_c/m_a;
01480 
01481   double dA = 1 + da*da;
01482   double dB = 2*( da*db - h - k*da );
01483   double dC = h*h + db*db-2*k*db + k*k - circle.getRadius()*circle.getRadius();
01484 
01485   iSol = Geometry::abcFormula( dA, dB, dC, &dSol1, &dSol2 );
01486 
01487   posSolution1->setVecPosition( dSol1, da*dSol1 + db );
01488   posSolution2->setVecPosition( dSol2, da*dSol2 + db );
01489   return iSol;
01490 
01491 }
01492 
01498 Line Line::getTangentLine( VecPosition pos )
01499 {
01500   // ay + bx + c = 0 -> y = (-b/a)x + (-c/a)
01501   // tangent: y = (a/b)*x + C1 -> by - ax + C2 = 0 => C2 = ax - by
01502   // with pos.y = y, pos.x = x
01503   return Line( m_b, -m_a, m_a*pos.getX() - m_b*pos.getY() );
01504 }
01505 
01509 VecPosition Line::getPointOnLineClosestTo( VecPosition pos )
01510 {
01511   Line l2 = getTangentLine( pos );  // get tangent line
01512   return getIntersection( l2 );     // and intersection between the two lines
01513 }
01514 
01519 double Line::getDistanceWithPoint( VecPosition pos )
01520 {
01521   return pos.getDistanceTo( getPointOnLineClosestTo( pos ) );
01522 }
01523 
01532 bool Line::isInBetween( VecPosition pos, VecPosition point1,VecPosition point2)
01533 {
01534   pos          = getPointOnLineClosestTo( pos ); // get closest point
01535   double dDist = point1.getDistanceTo( point2 ); // get distance between 2 pos
01536 
01537   // if the distance from both points to the projection is smaller than this
01538   // dist, the pos lies in between.
01539   return pos.getDistanceTo( point1 ) <= dDist &&
01540          pos.getDistanceTo( point2 ) <= dDist;
01541 }
01542 
01546 double Line::getYGivenX( double x )
01547 {
01548  if( m_a == 0 )
01549  {
01550    cerr << "(Line::getYGivenX) Cannot calculate Y coordinate: " ;
01551    show( cerr );
01552    cerr << endl;
01553    return 0;
01554  }
01555   // ay + bx + c = 0 ==> ay = -(b*x + c)/a
01556   return -(m_b*x+m_c)/m_a;
01557 }
01558 
01562 double Line::getXGivenY( double y )
01563 {
01564  if( m_b == 0 )
01565  {
01566    cerr << "(Line::getXGivenY) Cannot calculate X coordinate\n" ;
01567    return 0;
01568  }
01569   // ay + bx + c = 0 ==> bx = -(a*y + c)/a
01570   return -(m_a*y+m_c)/m_b;
01571 }
01572 
01577 Line Line::makeLineFromTwoPoints( VecPosition pos1, VecPosition pos2 )
01578 {
01579   // 1*y + bx + c = 0 => y = -bx - c
01580   // with -b the direction coefficient (or slope)
01581   // and c = - y - bx
01582   double dA, dB, dC;
01583   double dTemp = pos2.getX() - pos1.getX(); // determine the slope
01584   if( fabs(dTemp) < EPSILON )
01585   {
01586     // ay + bx + c = 0 with vertical slope=> a = 0, b = 1
01587     dA = 0.0;
01588     dB = 1.0;
01589   }
01590   else
01591   {
01592     // y = (-b)x -c with -b the slope of the line
01593     dA = 1.0;
01594     dB = -(pos2.getY() - pos1.getY())/dTemp;
01595   }
01596   // ay + bx + c = 0 ==> c = -a*y - b*x
01597   dC =  - dA*pos2.getY()  - dB * pos2.getX();
01598   return Line( dA, dB, dC );
01599 }
01600 
01605 Line Line::makeLineFromPositionAndAngle( VecPosition vec, AngDeg angle )
01606 {
01607   // calculate point somewhat further in direction 'angle' and make
01608   // line from these two points.
01609   return makeLineFromTwoPoints( vec, vec+VecPosition(1,angle,POLAR));
01610 }
01611 
01614 double Line::getACoefficient() const
01615 {
01616   return m_a;
01617 }
01618 
01621 double Line::getBCoefficient() const
01622 {
01623  return m_b;
01624 }
01625 
01628 double Line::getCCoefficient() const
01629 {
01630  return m_c;
01631 }
01632 
01633 /*****************************************************************************/
01634 /********************* CLASS RECTANGLE ***************************************/
01635 /*****************************************************************************/
01636 
01643 Rect::Rect( VecPosition pos, VecPosition pos2 )
01644 {
01645   setRectanglePoints( pos, pos2 );
01646 }
01647 
01652 void Rect::setRectanglePoints( VecPosition pos1, VecPosition pos2 )
01653 {
01654   m_posLeftTop.setX    ( max( pos1.getX(), pos2.getX() ) );
01655   m_posLeftTop.setY    ( min( pos1.getY(), pos2.getY() ) );
01656   m_posRightBottom.setX( min( pos1.getX(), pos2.getX() ) );
01657   m_posRightBottom.setY( max( pos1.getY(), pos2.getY() ) );
01658 }
01659 
01663 void Rect::show( ostream& os )
01664 {
01665   os << "rect(" << m_posLeftTop << " " << m_posRightBottom << ")";
01666 }
01667 
01672 bool Rect::isInside( VecPosition pos )
01673 {
01674   return pos.isBetweenX( m_posRightBottom.getX(), m_posLeftTop.getX() ) &&
01675          pos.isBetweenY( m_posLeftTop.getY(),     m_posRightBottom.getY() );
01676 
01677 }
01678 
01682 bool Rect::setPosLeftTop( VecPosition pos )
01683 {
01684   m_posLeftTop = pos;
01685   return true;
01686 }
01687 
01690 VecPosition Rect::getPosLeftTop(  )
01691 {
01692   return m_posLeftTop;
01693 }
01694 
01698 bool Rect::setPosRightBottom( VecPosition pos )
01699 {
01700   m_posRightBottom = pos;
01701   return true;
01702 }
01703 
01706 VecPosition Rect::getPosRightBottom(  )
01707 {
01708   return m_posRightBottom;
01709 }
01710 
01711 /*****************************************************************************/
01712 /********************** TESTING PURPOSES *************************************/
01713 /*****************************************************************************/
01714 
01715 /*
01716 #include<iostream.h>
01717 
01718 int main( void )
01719 {
01720   double dFirst = 1.0;
01721   double dRatio = 2.5;
01722   double dSum   = 63.4375;
01723   double dLength = 4.0;
01724 
01725   printf( "sum: %f\n", Geometry::getSumGeomSeries( dFirst, dRatio, dLength));
01726   printf( "length: %f\n", Geometry::getLengthGeomSeries( dFirst, dRatio, dSum));
01727 }
01728 
01729 int main( void )
01730 {
01731   Line l1(1,-1,3 );
01732   Line l2(1,-0.2,10 );
01733  Line l3 = Line::makeLineFromTwoPoints( VecPosition(1,-1), VecPosition(2,-2) );
01734  l3.show();
01735  cout << endl;
01736  l1.show();
01737  l2.show();
01738   l1.getIntersection( l2 ).show();
01739 }
01740 
01741 
01742 int main( void )
01743 {
01744   Line l( 1, -1, 0 );
01745   VecPosition s1, s2;
01746   int i = l.getCircleIntersectionPoints( Circle( VecPosition(1,1),1) &s1,&s2 );
01747   printf( "number of solutions: %d\n", i );
01748   if( i == 2 )
01749   {
01750     cout << s1 << " " << s2 ;
01751   }
01752   else if( i == 1 )
01753   {
01754     cout << s1;
01755   }
01756   cout << "line: " << l;
01757 }
01758 
01759 int main( void )
01760 {
01761   Circle c11( VecPosition( 10, 0 ), 10);
01762   Circle c12( VecPosition( 40, 3 ), 40 );
01763   Circle c21( VecPosition(  0,0 ), 5);
01764   Circle c22( VecPosition(  3,0 ), 40 );
01765 
01766   VecPosition p1, p2;
01767 
01768   cout << c11.getIntersectionArea( c21 ) << endl;
01769   cout << c12.getIntersectionArea( c21 ) << endl;
01770   cout << c22.getIntersectionArea( c11 ) << endl;
01771   cout << c12.getIntersectionArea( c22 ) << endl;
01772   return 0;
01773 }
01774 
01775 int main( void )
01776 {
01777   cout << getBisectorTwoAngles( -155.3, 179.0 ) << endl;
01778   cout << getBisectorTwoAngles( -179.3, 179.0 ) << endl;
01779 }
01780 */

Generated on Fri Nov 7 11:45:39 2003 for UvA Trilearn 2003 Base Code by doxygen1.2.12 written by Dimitri van Heesch, © 1997-2001