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

Geometry.C

Go to the documentation of this file.
00001 /*
00002 Copyright (c) 2000,2001, 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 */
00050 #include "Geometry.h"
00051 #include <stdio.h>    // needed for sprintf
00052 
00057 int sign( double d1 )
00058 {
00059   return (d1>0)?1:-1;
00060 }
00061 
00066 double max( double d1, double d2 )
00067 {
00068   return (d1>d2)?d1:d2;
00069 }
00070 
00075 double min( double d1, double d2 )
00076 {
00077   return (d1<d2)?d1:d2;
00078 }
00079 
00080 
00085 AngDeg Rad2Deg( AngRad x )
00086 {
00087   return ( x * 180 / M_PI );
00088 }
00089 
00094 AngRad Deg2Rad( AngDeg x )
00095 {
00096   return ( x * M_PI / 180 );
00097 }
00098 
00103 double cosDeg( AngDeg x )
00104 {
00105   return ( cos( Deg2Rad( x ) ) );
00106 }
00107 
00112 double sinDeg( AngDeg x )
00113 {
00114   return ( sin( Deg2Rad( x ) ) );
00115 }
00116 
00121 double tanDeg( AngDeg x )
00122 {
00123   return ( tan( Deg2Rad( x ) ) );
00124 }
00125 
00130 AngDeg atanDeg( double x )
00131 {
00132   return ( Rad2Deg( atan( x ) ) );
00133 }
00134 
00143 double atan2Deg( double x, double y )
00144 {
00145   if( fabs( x ) < EPSILON && fabs( y ) < EPSILON )
00146     return ( 0.0 );
00147 
00148   return ( Rad2Deg( atan2( x, y ) ) );
00149 }
00150 
00155 AngDeg acosDeg( double x )
00156 {
00157   if( x >= 1 )
00158     return ( 0.0 );
00159   else if( x <= -1 )
00160     return ( 180.0 );
00161 
00162   return ( Rad2Deg( acos( x ) ) );
00163 }
00164 
00169 AngDeg asinDeg( double x )
00170 {
00171   if( x >= 1 )
00172     return ( 90.0 );
00173   else if ( x <= -1 )
00174     return ( -90.0 );
00175 
00176   return ( Rad2Deg( asin( x ) ) );
00177 }
00178 
00187 bool isAngInInterval( AngDeg ang, AngDeg angMin, AngDeg angMax )
00188 {
00189   // convert all angles to interval 0..360
00190   if( ( ang    + 360 ) < 360 ) ang    += 360;
00191   if( ( angMin + 360 ) < 360 ) angMin += 360;
00192   if( ( angMax + 360 ) < 360 ) angMax += 360;
00193 
00194   if( angMin < angMax ) // 0 ---false-- angMin ---true-----angMax---false--360
00195     return angMin < ang && ang < angMax ;
00196   else                  // 0 ---true--- angMax ---false----angMin---true---360
00197     return !( angMax < ang && ang < angMin );
00198 }
00199 
00206 AngDeg getBisectorTwoAngles( AngDeg angMin, AngDeg angMax )
00207 {
00208   // separate sine and cosine part to circumvent boundary problem
00209   return VecPosition::normalizeAngle(
00210             atan2Deg( (sinDeg( angMin) + sinDeg( angMax ) )/2.0,
00211                       (cosDeg( angMin) + cosDeg( angMax ) )/2.0 ) );
00212 }
00213 
00214 /******************************************************************************/
00215 /********************   CLASS VECPOSITION   ***********************************/
00216 /******************************************************************************/
00217 
00231 VecPosition::VecPosition( double x, double y, CoordSystemT cs )
00232 {
00233   setVecPosition( x, y, cs );
00234 }
00235 
00240 VecPosition VecPosition::operator - ( )
00241 {
00242   return ( VecPosition( -m_x, -m_y ) );
00243 }
00244 
00253 VecPosition VecPosition::operator + ( const double &d )
00254 {
00255   return ( VecPosition( m_x + d, m_y + d ) );
00256 }
00257 
00263 VecPosition VecPosition::operator + ( const VecPosition &p )
00264 {
00265   return ( VecPosition( m_x + p.m_x, m_y + p.m_y ) );
00266 }
00267 
00276 VecPosition VecPosition::operator - ( const double &d )
00277 {
00278   return ( VecPosition( m_x - d, m_y - d ) );
00279 }
00280 
00288 VecPosition VecPosition::operator - ( const VecPosition &p )
00289 {
00290   return ( VecPosition( m_x - p.m_x, m_y - p.m_y ) );
00291 }
00292 
00300 VecPosition VecPosition::operator * ( const double &d  )
00301 {
00302   return ( VecPosition( m_x * d, m_y * d  ) );
00303 }
00304 
00311 VecPosition VecPosition::operator * ( const VecPosition &p )
00312 {
00313   return ( VecPosition( m_x * p.m_x, m_y * p.m_y ) );
00314 }
00315 
00322 VecPosition VecPosition::operator / ( const double &d )
00323 {
00324   return ( VecPosition( m_x / d, m_y / d  ) );
00325 }
00326 
00332 VecPosition VecPosition::operator / ( const VecPosition &p )
00333 {
00334   return ( VecPosition( m_x / p.m_x, m_y / p.m_y ) );
00335 }
00336 
00342 void VecPosition::operator = ( const double &d )
00343 {
00344   m_x = d;
00345   m_y = d;
00346 }
00347 
00353 void VecPosition::operator +=( const VecPosition &p )
00354 {
00355   m_x += p.m_x;
00356   m_y += p.m_y;
00357 }
00358 
00365 void VecPosition::operator += ( const double &d )
00366 {
00367   m_x += d;
00368   m_y += d;
00369 }
00370 
00377 void VecPosition::operator -=( const VecPosition &p )
00378 {
00379   m_x -= p.m_x;
00380   m_y -= p.m_y;
00381 }
00382 
00389 void VecPosition::operator -=( const double &d )
00390 {
00391   m_x -= d;
00392   m_y -= d;
00393 }
00394 
00401 void VecPosition::operator *=( const VecPosition &p )
00402 {
00403   m_x *= p.m_x;
00404   m_y *= p.m_y;
00405 }
00406 
00413 void VecPosition::operator *=( const double &d )
00414 {
00415   m_x *= d;
00416   m_y *= d;
00417 }
00418 
00424 void VecPosition::operator /=( const VecPosition &p )
00425 {
00426   m_x /= p.m_x;
00427   m_y /= p.m_y;
00428 }
00429 
00436 void VecPosition::operator /=( const double &d )
00437 {
00438   m_x /= d;
00439   m_y /= d;
00440 }
00441 
00448 bool VecPosition::operator !=( const VecPosition &p )
00449 {
00450   return ( ( m_x != p.m_x ) || ( m_y != p.m_y ) );
00451 }
00452 
00460 bool VecPosition::operator !=( const double &d )
00461 {
00462   return ( ( m_x != d ) || ( m_y != d ) );
00463 }
00464 
00471 bool VecPosition::operator ==( const VecPosition &p )
00472 {
00473   return ( ( m_x == p.m_x ) && ( m_y == p.m_y ) );
00474 }
00475 
00483 bool VecPosition::operator ==( const double &d )
00484 {
00485   return ( ( m_x == d ) && ( m_y == d ) );
00486 }
00487 
00495 ostream& operator <<( ostream &os, VecPosition v )
00496 {
00497   return ( os << "( " << v.m_x << ", " << v.m_y << " )" );
00498 }
00499 
00504 void VecPosition::show( CoordSystemT cs )
00505 {
00506   if( cs == CARTESIAN )
00507     cout << *this << endl;
00508   else
00509     cout << "( r: " << getMagnitude( ) << ", phi: " << getDirection( ) << "  )";
00510 }
00511 
00518 string VecPosition::str( CoordSystemT cs )
00519 {
00520   char buf[ 1024 ];
00521 
00522   if( cs == CARTESIAN )
00523     sprintf( buf, "( %f, %f )", getX( ), getY( ) );
00524   else
00525     sprintf( buf, "( r: %f, phi: %f )", getMagnitude( ), getDirection( ) );
00526 
00527   string str( buf );
00528   return ( str );
00529 }
00530 
00534 bool VecPosition::setX( double dX )
00535 {
00536   m_x = dX;
00537   return ( true );
00538 }
00539 
00542 double VecPosition::getX( ) const
00543 {
00544   return ( m_x );
00545 }
00546 
00550 bool VecPosition::setY( double dY )
00551 {
00552   m_y = dY;
00553   return ( true );
00554 }
00555 
00558 double VecPosition::getY( ) const
00559 {
00560   return ( m_y );
00561 }
00562 
00572 void VecPosition::setVecPosition( double dX = 0, double dY = 0, CoordSystemT cs)
00573 {
00574   if( cs == CARTESIAN )
00575   {
00576     m_x = dX;
00577     m_y = dY;
00578   }
00579   else
00580     *this = getVecPositionFromPolar( dX, dY );
00581 }
00582 
00589 double VecPosition::getDistanceTo( const VecPosition p )
00590 {
00591   return ( ( *this - p ).getMagnitude( ) );
00592 }
00593 
00602 VecPosition VecPosition::setMagnitude( double d )
00603 {
00604   if( getMagnitude( ) > EPSILON )
00605      ( *this ) *= ( d / getMagnitude( ) );
00606 
00607   return ( *this );
00608 }
00609 
00614 double VecPosition::getMagnitude( ) const
00615 {
00616   return ( sqrt( m_x * m_x + m_y * m_y ) );
00617 }
00618 
00625 AngDeg VecPosition::getDirection( ) const
00626 {
00627   return ( atan2Deg( m_y, m_x ) );
00628 }
00629 
00636 bool VecPosition::isInFrontOf( const VecPosition &p )
00637 {
00638   return ( ( m_x > p.getX( ) ) ? true : false );
00639 }
00640 
00646 bool VecPosition::isInFrontOf( const double &d )
00647 {
00648   return ( ( m_x > d ) ? true : false );
00649 }
00650 
00657 bool VecPosition::isBehindOf( const VecPosition &p )
00658 {
00659   return ( ( m_x < p.getX( ) ) ? true : false );
00660 }
00661 
00667 bool VecPosition::isBehindOf( const double &d )
00668 {
00669   return ( ( m_x < d ) ? true : false );
00670 }
00671 
00678 bool VecPosition::isLeftOf( const VecPosition &p )
00679 {
00680   return ( ( m_y < p.getY( ) ) ? true : false );
00681 }
00682 
00688 bool VecPosition::isLeftOf( const double &d )
00689 {
00690   return ( ( m_y < d ) ? true : false );
00691 }
00692 
00699 bool VecPosition::isRightOf( const VecPosition &p )
00700 {
00701   return ( ( m_y > p.getY( ) ) ? true : false );
00702 }
00703 
00709 bool VecPosition::isRightOf( const double &d )
00710 {
00711   return ( ( m_y > d ) ? true : false );
00712 }
00713 
00721 bool VecPosition::isBetweenX( const VecPosition &p1, const VecPosition &p2 )
00722 {
00723   return ( ( isInFrontOf( p1 ) && isBehindOf( p2 ) ) ? true : false );
00724 }
00725 
00733 bool VecPosition::isBetweenX( const double &d1, const double &d2 )
00734 {
00735   return ( ( isInFrontOf( d1 ) && isBehindOf( d2 ) ) ? true : false );
00736 }
00737 
00746 bool VecPosition::isBetweenY( const VecPosition &p1, const VecPosition &p2 )
00747 {
00748   return ( ( isRightOf( p1 ) && isLeftOf( p2 ) ) ? true : false );
00749 }
00750 
00759 bool VecPosition::isBetweenY( const double &d1, const double &d2 )
00760 {
00761   return ( ( isRightOf( d1 ) && isLeftOf( d2 ) ) ? true : false );
00762 }
00763 
00768 VecPosition VecPosition::normalize( )
00769 {
00770   return ( setMagnitude( 1.0 ) );
00771 }
00772 
00783 VecPosition VecPosition::rotate( AngDeg angle )
00784 {
00785   // determine the polar representation of the current VecPosition
00786   double dMag    = this->getMagnitude( );
00787   double dNewDir = this->getDirection( ) + angle;  // add rotation angle to phi
00788   setVecPosition( dMag, dNewDir, POLAR );          // convert back to Cartesian
00789   return ( *this );
00790 }
00791 
00804 VecPosition VecPosition::globalToRelative( VecPosition origin, AngDeg ang )
00805 {
00806   // convert global coordinates into relative coordinates by aligning relative
00807   // frame and world frame. First perform translation to make origins of both
00808   // frames coincide. Then perform rotation to make axes of both frames coincide
00809   // (use negative angle since you rotate relative frame to world frame).
00810   *this -= origin;
00811   return ( rotate( -ang ) );
00812 }
00813 
00826 VecPosition VecPosition::relativeToGlobal( VecPosition origin, AngDeg ang )
00827 {
00828   // convert relative coordinates into global coordinates by aligning world
00829   // frame and relative frame. First perform rotation to make axes of both
00830   // frames coincide (use positive angle since you rotate world frame to
00831   // relative frame). Then perform translation to make origins of both frames
00832   // coincide.
00833   rotate( ang );
00834   *this += origin;
00835   return ( *this );
00836 }
00837 
00847 VecPosition VecPosition::getVecPositionOnLineFraction( VecPosition &p,
00848                                                        double      dFrac )
00849 {
00850   // determine point on line that lies at fraction dFrac of whole line
00851   // example: this --- 0.25 ---------  p
00852   // formula: this + dFrac * ( p - this ) = this - dFrac * this + dFrac * p =
00853   //          ( 1 - dFrac ) * this + dFrac * p
00854   return ( ( *this ) * ( 1.0 - dFrac ) + ( p * dFrac ) );
00855 }
00856 
00865 VecPosition VecPosition::getVecPositionFromPolar( double dMag, AngDeg ang )
00866 {
00867   // cos(phi) = x/r <=> x = r*cos(phi); sin(phi) = y/r <=> y = r*sin(phi)
00868   return ( VecPosition( dMag * cosDeg( ang ), dMag * sinDeg( ang ) ) );
00869 }
00870 
00875 AngDeg VecPosition::normalizeAngle( AngDeg angle )
00876 {
00877   while( angle > 180.0  ) angle -= 360.0;
00878   while( angle < -180.0 ) angle += 360.0;
00879 
00880   return ( angle );
00881 }
00882 
00883 
00884 /******************************************************************************/
00885 /*********************** CLASS GEOMETRY ***************************************/
00886 /******************************************************************************/
00887 
00898 double Geometry::getLengthGeomSeries( double dFirst, double dRatio, double dSum )
00899 {
00900   if( dRatio < 0 )
00901     cerr << "(Geometry:getLengthGeomSeries): negative ratio" << endl;
00902 
00903   // s = a + ar + ar^2 + .. + ar^n-1 and thus sr = ar + ar^2 + .. + ar^n
00904   // subtract: sr - s = - a + ar^n) =>  s(1-r)/a + 1 = r^n = temp
00905   // log r^n / n = n log r / log r = n = length
00906   double temp = (dSum * ( dRatio - 1 ) / dFirst) + 1;
00907   if( temp <= 0 )
00908     return -1.0;
00909   return log( temp ) / log( dRatio ) ;
00910 }
00911 
00922 double Geometry::getSumGeomSeries( double dFirst, double dRatio, double dLength)
00923 {
00924   // s = a + ar + ar^2 + .. + ar^n-1 and thus sr = ar + ar^2 + .. + ar^n
00925   // subtract: s - sr = a - ar^n) =>  s = a(1-r^n)/(1-r)
00926   return dFirst * ( 1 - pow( dRatio, dLength ) ) / ( 1 - dRatio ) ;
00927 }
00928 
00939 double Geometry::getSumInfGeomSeries( double dFirst, double dRatio )
00940 {
00941   if( dRatio > 1 )
00942     cerr << "(Geometry:CalcLengthGeomSeries): series does not converge" << endl;
00943 
00944   // s = a(1-r^n)/(1-r) with n->inf and 0<r<1 => r^n = 0
00945   return dFirst / ( 1 - dRatio );
00946 }
00947 
00958 double Geometry::getFirstGeomSeries( double dSum, double dRatio, double dLength)
00959 {
00960   // s = a + ar + ar^2 + .. + ar^n-1 and thus sr = ar + ar^2 + .. + ar^n
00961   // subtract: s - sr = a - ar^n) =>  s = a(1-r^n)/(1-r) => a = s*(1-r)/(1-r^n)
00962   return dSum *  ( 1 - dRatio )/( 1 - pow( dRatio, dLength ) ) ;
00963 }
00964 
00975 double Geometry::getFirstInfGeomSeries( double dSum, double dRatio )
00976 {
00977   if( dRatio > 1 )
00978     cerr << "(Geometry:getFirstInfGeomSeries):series does not converge" << endl;
00979 
00980   // s = a(1-r^n)/(1-r) with r->inf and 0<r<1 => r^n = 0 => a = s ( 1 - r)
00981   return dSum * ( 1 - dRatio );
00982 }
00983 
00993 int Geometry::abcFormula(double a, double b, double c, double *s1, double *s2)
00994 {
00995   double dDiscr = b*b - 4*a*c;       // discriminant is b^2 - 4*a*c
00996   if (fabs(dDiscr) < EPSILON )       // if discriminant = 0
00997   {
00998     *s1 = -b / (2 * a);              //  only one solution
00999     return 1;
01000   }
01001   else if (dDiscr < 0)               // if discriminant < 0
01002     return 0;                        //  no solutions
01003   else                               // if discriminant > 0
01004   {
01005     dDiscr = sqrt(dDiscr);           //  two solutions
01006     *s1 = (-b + dDiscr ) / (2 * a);
01007     *s2 = (-b - dDiscr ) / (2 * a);
01008     return 2;
01009   }
01010 }
01011 
01012 /******************************************************************************/
01013 /********************** CLASS CIRCLE ******************************************/
01014 /******************************************************************************/
01015 
01020 Circle::Circle( VecPosition pos, double dR )
01021 {
01022   setCircle( pos, dR );
01023 }
01024 
01027 Circle::Circle( )
01028 {
01029   setCircle( VecPosition(-1000.0,-1000.0), 0);
01030 }
01031 
01036 void Circle::show( ostream& os)
01037 {
01038   os << "c:" << m_posCenter << ", r:" << m_dRadius;
01039 }
01040 
01046 bool Circle::setCircle( VecPosition pos, double dR )
01047 {
01048   setCenter( pos );
01049   return setRadius( dR  );
01050 }
01054 bool Circle::setRadius( double dR )
01055 {
01056   if( dR > 0 )
01057   {
01058     m_dRadius = dR;
01059     return true;
01060   }
01061   else
01062   {
01063     m_dRadius = 0.0;
01064     return false;
01065   }
01066 }
01067 
01070 double Circle::getRadius()
01071 {
01072   return m_dRadius;
01073 }
01074 
01078 bool Circle::setCenter( VecPosition pos )
01079 {
01080   m_posCenter = pos;
01081   return true;
01082 }
01083 
01086 VecPosition Circle::getCenter()
01087 {
01088   return m_posCenter;
01089 }
01090 
01093 double Circle::getCircumference()
01094 {
01095   return 2.0*M_PI*getRadius();
01096 }
01097 
01100 double Circle::getArea()
01101 {
01102   return M_PI*getRadius()*getRadius();
01103 }
01104 
01110 bool Circle::isInside( VecPosition pos )
01111 {
01112   return m_posCenter.getDistanceTo( pos ) < getRadius() ;
01113 }
01120 int Circle::getIntersectionPoints( Circle c, VecPosition *p1, VecPosition *p2)
01121 {
01122     double x0, y0, r0;
01123     double x1, y1, r1;
01124 
01125     x0 = getCenter( ).getX();
01126     y0 = getCenter( ).getY();
01127     r0 = getRadius( );
01128     x1 = c.getCenter( ).getX();
01129     y1 = c.getCenter( ).getY();
01130     r1 = c.getRadius( );
01131 
01132     double      d, dx, dy, h, a, x, y, p2_x, p2_y;
01133 
01134     // first calculate distance between two centers circles P0 and P1.
01135     dx = x1 - x0;
01136     dy = y1 - y0;
01137     d = sqrt(dx*dx + dy*dy);
01138 
01139     // normalize differences
01140     dx /= d; dy /= d;
01141 
01142     // a is distance between p0 and point that is the intersection point P2
01143     // that intersects P0-P1 and the line that crosses the two intersection
01144     // points P3 and P4.
01145     // Define two triangles: P0,P2,P3 and P1,P2,P3.
01146     // with distances a, h, r0 and b, h, r1 with d = a + b
01147     // We know a^2 + h^2 = r0^2 and b^2 + h^2 = r1^2 which then gives
01148     // a^2 + r1^2 - b^2 = r0^2 with d = a + b ==> a^2 + r1^2 - (d-a)^2 = r0^2
01149     // ==> r0^2 + d^2 - r1^2 / 2*d
01150     a = (r0*r0 + d*d - r1*r1) / (2.0 * d);
01151 
01152     // h is then a^2 + h^2 = r0^2 ==> h = sqrt( r0^2 - a^2 )
01153     double      arg = r0*r0 - a*a;
01154     h = (arg > 0.0) ? sqrt(arg) : 0.0;
01155 
01156     // First calculate P2
01157     p2_x = x0 + a * dx;
01158     p2_y = y0 + a * dy;
01159 
01160     // and finally the two intersection points
01161     x =  p2_x - h * dy;
01162     y =  p2_y + h * dx;
01163     p1->setVecPosition( x, y );
01164     x =  p2_x + h * dy;
01165     y =  p2_y - h * dx;
01166     p2->setVecPosition( x, y );
01167 
01168     return (arg < 0.0) ? 0 : ((arg == 0.0 ) ? 1 :  2);
01169 }
01170 
01174 double Circle::getIntersectionArea( Circle c )
01175 {
01176   VecPosition pos1, pos2, pos3;
01177   double d, h, dArea;
01178   AngDeg ang;
01179 
01180   d = getCenter().getDistanceTo( c.getCenter() ); // dist between two centers
01181   if( d > c.getRadius() + getRadius() )           // larger than sum radii
01182     return 0.0;                                   // circles do not intersect
01183   if( d <= fabs(c.getRadius() - getRadius() ) )   // one totally in the other
01184   {
01185     double dR = min( c.getRadius(), getRadius() );// return area smallest circle
01186     return M_PI*dR*dR;
01187   }
01188 
01189   int iNrSol = getIntersectionPoints( c, &pos1, &pos2 );
01190   if( iNrSol != 2 )
01191     return 0.0;
01192 
01193   // the intersection area of two circles can be divided into two segments:
01194   // left and right of the line between the two intersection points p1 and p2.
01195   // The outside area of each segment can be calculated by taking the part
01196   // of the circle pie excluding the triangle from the center to the
01197   // two intersection points.
01198   // The pie equals pi*r^2 * rad(2*ang) / 2*pi = 0.5*rad(2*ang)*r^2 with ang
01199   // the angle between the center c of the circle and one of the two
01200   // intersection points. Thus the angle between c and p1 and c and p3 where
01201   // p3 is the point that lies halfway between p1 and p2.
01202   // This can be calculated using ang = asin( d / r ) with d the distance
01203   // between p1 and p3 and r the radius of the circle.
01204   // The area of the triangle is 2*0.5*h*d.
01205 
01206   pos3 = pos1.getVecPositionOnLineFraction( pos2, 0.5 );
01207   d = pos1.getDistanceTo( pos3 );
01208   h = pos3.getDistanceTo( getCenter() );
01209   ang = asin( d / getRadius() );
01210 
01211   dArea = ang*getRadius()*getRadius();
01212   dArea = dArea - d*h;
01213 
01214   // and now for the other segment the same story
01215   h = pos3.getDistanceTo( c.getCenter() );
01216   ang = asin( d / c.getRadius() );
01217   dArea = dArea + ang*c.getRadius()*c.getRadius();
01218   dArea = dArea - d*h;
01219 
01220   return dArea;
01221 }
01222 
01223 
01224 /******************************************************************************/
01225 /***********************  CLASS LINE *******************************************/
01226 /******************************************************************************/
01227 
01233 Line::Line( double dA, double dB, double dC )
01234 {
01235   m_a = dA;
01236   m_b = dB;
01237   m_c = dC;
01238 }
01239 
01245 ostream& operator <<(ostream & os, Line l)
01246 {
01247   double a = l.getACoefficient();
01248   double b = l.getBCoefficient();
01249   double c = l.getCCoefficient();
01250 
01251   // ay + bx + c = 0 -> y = -b/a x - c/a
01252   if( a == 0 )
01253     os << "x = " << -c/b;
01254   else
01255   {
01256     os << "y = ";
01257     if( b != 0 )
01258       os << -b/a << "x ";
01259     if( c > 0 )
01260        os << "- " <<  fabs(c/a);
01261     else if( c < 0 )
01262        os << "+ " <<  fabs(c/a);
01263   }
01264   return os;
01265 }
01266 
01269 void Line::show( ostream& os)
01270 {
01271   os << *this;
01272 }
01273 
01278 VecPosition Line::getIntersection( Line line )
01279 {
01280   VecPosition pos;
01281   double x, y;
01282 
01283   if( m_b == line.getBCoefficient() ) // lines are parallel, no intersection
01284   {
01285     return pos;
01286   }
01287   if( m_a == 0 )               // bx + c = 0 and a2*y + b2*x + c2 = 0 ==> x = -c/b
01288   {                          // calculate x using the current line
01289     x = -m_c/m_b;                // and calculate the y using the second line
01290     y = line.getYGivenX(x);
01291   }
01292   else if( line.getACoefficient() == 0 )
01293   {                         // ay + bx + c = 0 and b2*x + c2 = 0 ==> x = -c2/b2
01294    x = -line.getCCoefficient()/line.getBCoefficient(); // calculate x using
01295    y = getYGivenX(x);       // 2nd line and calculate y using current line
01296   }
01297   // ay + bx + c = 0 and a2y + b2*x + c2 = 0
01298   // y = (-b2/a2)x - c2/a2
01299   // bx = -a*y - c =>  bx = -a*(-b2/a2)x -a*(-c2/a2) - c ==>
01300   // ==> a2*bx = a*b2*x + a*c2 - a2*c ==> x = (a*c2 - a2*c)/(a2*b - a*b2)
01301   // calculate x using the above formula and the y using the current line
01302   else
01303   {
01304     x = (m_a*line.getCCoefficient() - line.getACoefficient()*m_c)/
01305                     (line.getACoefficient()*m_b - m_a*line.getBCoefficient());
01306     y = getYGivenX(x);
01307   }
01308 
01309   return VecPosition( x, y );
01310 }
01311 
01312 
01320 int Line::getCircleIntersectionPoints( Circle circle,
01321               VecPosition *posSolution1, VecPosition *posSolution2 )
01322 {
01323   int    iSol;
01324   double dSol1, dSol2;
01325   double h = circle.getCenter().getX();
01326   double k = circle.getCenter().getY();
01327 
01328   // line:   x = -c/b (if a = 0)
01329   // circle: (x-h)^2 + (y-k)^2 = r^2, with h = center.x and k = center.y
01330   // fill in:(-c/b-h)^2 + y^2 -2ky + k^2 - r^2 = 0
01331   //         y^2 -2ky + (-c/b-h)^2 + k^2 - r^2 = 0
01332   // and determine solutions for y using abc-formula
01333   if( fabs(m_a) < EPSILON )
01334   {
01335     iSol = Geometry::abcFormula( 1, -2*k, ((-m_c/m_b) - h)*((-m_c/m_b) - h)
01336               + k*k - circle.getRadius()*circle.getRadius(), &dSol1, &dSol2);
01337     posSolution1->setVecPosition( (-m_c/m_b), dSol1 );
01338     posSolution2->setVecPosition( (-m_c/m_b), dSol2 );
01339     return iSol;
01340   }
01341 
01342   // ay + bx + c = 0 => y = -b/a x - c/a, with da = -b/a and db = -c/a
01343   // circle: (x-h)^2 + (y-k)^2 = r^2, with h = center.x and k = center.y
01344   // fill in:x^2 -2hx + h^2 + (da*x-db)^2 -2k(da*x-db) + k^2 - r^2 = 0
01345   //         x^2 -2hx + h^2 + da^2*x^2 + 2da*db*x + db^2 -2k*da*x -2k*db
01346   //                                                         + k^2 - r^2 = 0
01347   //         (1+da^2)*x^2 + 2(da*db-h-k*da)*x + h2 + db^2  -2k*db + k^2 - r^2 = 0
01348   // and determine solutions for x using abc-formula
01349   // fill in x in original line equation to get y coordinate
01350   double da = -m_b/m_a;
01351   double db = -m_c/m_a;
01352 
01353   double dA = 1 + da*da;
01354   double dB = 2*( da*db - h - k*da );
01355   double dC = h*h + db*db - 2*k*db + k*k - circle.getRadius()*circle.getRadius();
01356 
01357   iSol = Geometry::abcFormula( dA, dB, dC, &dSol1, &dSol2 );
01358 
01359   posSolution1->setVecPosition( dSol1, da*dSol1 + db );
01360   posSolution2->setVecPosition( dSol2, da*dSol2 + db );
01361   return iSol;
01362 
01363 }
01364 
01370 Line Line::getTangentLine( VecPosition pos )
01371 {
01372   // ay + bx + c = 0 -> y = (-b/a)x + (-c/a)
01373   // tangent: y = (a/b)*x + C1 -> by - ax + C2 = 0 => C2 = ax - by
01374   // with pos.y = y, pos.x = x
01375   return Line( m_b, -m_a, m_a*pos.getX() - m_b*pos.getY() );
01376 }
01377 
01381 VecPosition Line::getPointOnLineClosestTo( VecPosition pos )
01382 {
01383   Line l2 = getTangentLine( pos );  // get tangent line
01384   return getIntersection( l2 );     // and intersection between the two lines
01385 }
01386 
01391 double Line::getDistanceWithPoint( VecPosition pos )
01392 {
01393   return pos.getDistanceTo( getPointOnLineClosestTo( pos ) );
01394 }
01395 
01403 bool Line::isInBetween( VecPosition pos, VecPosition point1, VecPosition point2)
01404 {
01405   pos          = getPointOnLineClosestTo( pos ); // get closest point
01406   double dDist = point1.getDistanceTo( point2 ); // get distance between 2 pos
01407   // if the distance from both points to the projection is smaller than this
01408   // dist, the pos lies in between.
01409   return pos.getDistanceTo( point1 ) <= dDist &&
01410          pos.getDistanceTo( point2 ) <= dDist;
01411 }
01412 
01416 double Line::getYGivenX( double x )
01417 {
01418  if( m_a == 0 )
01419  {
01420    cerr << "(Line::getYGivenX) Cannot calculate Y coordinate: " ;
01421    show( cerr );
01422    cerr << endl;
01423    return 0;
01424  }
01425   // ay + bx + c = 0 ==> ay = -(b*x + c)/a
01426   return -(m_b*x+m_c)/m_a;
01427 }
01428 
01432 double Line::getXGivenY( double y )
01433 {
01434  if( m_b == 0 )
01435  {
01436    cerr << "(Line::getXGivenY) Cannot calculate X coordinate\n" ;
01437    return 0;
01438  }
01439   // ay + bx + c = 0 ==> bx = -(a*y + c)/a
01440   return -(m_a*y+m_c)/m_b;
01441 }
01442 
01447 Line Line::makeLineFromTwoPoints( VecPosition pos1, VecPosition pos2 )
01448 {
01449   // 1*y + bx + c = 0 => y = -bx - c
01450   // with -b the direction coefficient (or slope)
01451   // and c = - y - bx
01452   double dA=1.0, dB, dC;
01453   double dTemp = pos2.getX() - pos1.getX(); // determine the slope
01454   if( fabs(dTemp) < EPSILON )
01455   {
01456     // ay + bx + c = 0 with vertical slope=> a = 0, b = 1
01457     dA = 0.0;
01458     dB = 1.0;
01459   }
01460   else
01461   {
01462     // y = (-b)x -c with -b the slope of the line
01463     dA = 1.0;
01464     dB = -(pos2.getY() - pos1.getY())/dTemp;
01465   }
01466   // ay + bx + c = 0 ==> c = -a*y - b*x
01467   dC =  - dA*pos2.getY()  - dB * pos2.getX();
01468   return Line( dA, dB, dC );
01469 }
01470 
01475 Line Line::makeLineFromPositionAndAngle( VecPosition vec, AngDeg angle )
01476 {
01477   // calculate point somewhat further in direction 'angle' and make
01478   // line from these two points.
01479   return makeLineFromTwoPoints( vec, vec+VecPosition(1,angle,POLAR));
01480 }
01481 
01484 double Line::getACoefficient() const
01485 {
01486   return m_a;
01487 }
01488 
01491 double Line::getBCoefficient() const
01492 {
01493  return m_b;
01494 }
01495 
01498 double Line::getCCoefficient() const
01499 {
01500  return m_c;
01501 }
01502 
01503 /******************************************************************************/
01504 /********************** CLASS RECTANGLE ***************************************/
01505 /******************************************************************************/
01506 
01513 Rectangle::Rectangle( VecPosition pos, VecPosition pos2 )
01514 {
01515   setRectanglePoints( pos, pos2 );
01516 }
01517 
01522 void Rectangle::setRectanglePoints( VecPosition pos1, VecPosition pos2 )
01523 {
01524   m_posLeftTop.setX    ( max( pos1.getX(), pos2.getX() ) );
01525   m_posLeftTop.setY    ( min( pos1.getY(), pos2.getY() ) );
01526   m_posRightBottom.setX( min( pos1.getX(), pos2.getX() ) );
01527   m_posRightBottom.setY( max( pos1.getY(), pos2.getY() ) );
01528 }
01529 
01533 void Rectangle::show( ostream& os )
01534 {
01535   cout << "rect(" << m_posLeftTop << " " << m_posRightBottom << ")";
01536 }
01537 
01542 bool Rectangle::isInside( VecPosition pos )
01543 {
01544   return pos.isBetweenX( m_posRightBottom.getX(), m_posLeftTop.getX() ) &&
01545          pos.isBetweenY( m_posLeftTop.getY(),     m_posRightBottom.getY() );
01546 
01547 }
01548 
01552 bool Rectangle::setPosLeftTop( VecPosition pos )
01553 {
01554   m_posLeftTop = pos;
01555   return true;
01556 }
01557 
01560 VecPosition Rectangle::getPosLeftTop( VecPosition pos )
01561 {
01562   return m_posLeftTop;
01563 }
01564 
01568 bool Rectangle::setPosRightBottom( VecPosition pos )
01569 {
01570   m_posRightBottom = pos;
01571   return true;
01572 }
01573 
01576 VecPosition Rectangle::getPosRightBottom( VecPosition pos )
01577 {
01578   return m_posRightBottom;
01579 }
01580 
01581 /******************************************************************************/
01582 /********************** TESTING PURPOSES *************************************/
01583 /******************************************************************************/
01584 
01585 /*
01586 #include<iostream.h>
01587 
01588 int main( void )
01589 {
01590   double dFirst = 1.0;
01591   double dRatio = 2.5;
01592   double dSum   = 63.4375;
01593   double dLength = 4.0;
01594 
01595   printf( "sum: %f\n", Geometry::getSumGeomSeries( dFirst, dRatio, dLength));
01596   printf( "length: %f\n", Geometry::getLengthGeomSeries( dFirst, dRatio, dSum));
01597 }
01598 
01599 int main( void )
01600 {
01601   Line l1(1,-1,3 );
01602   Line l2(1,-0.2,10 );
01603  Line l3 = Line::makeLineFromTwoPoints( VecPosition(1,-1), VecPosition(2,-2) );
01604  l3.show();
01605  cout << endl;
01606  l1.show();
01607  l2.show();
01608   l1.getIntersection( l2 ).show();
01609 }
01610 
01611 
01612 int main( void )
01613 {
01614   Line l( 1, -1, 0 );
01615   VecPosition s1, s2;
01616   int i = l.getCircleIntersectionPoints( Circle( VecPosition(1,1),1) &s1, &s2 );
01617   printf( "number of solutions: %d\n", i );
01618   if( i == 2 )
01619   {
01620     cout << s1 << " " << s2 ;
01621   }
01622   else if( i == 1 )
01623   {
01624     cout << s1;
01625   }
01626   cout << "line: " << l;
01627 }
01628 
01629 int main( void )
01630 {
01631   Circle c11( VecPosition( 10, 0 ), 10);
01632   Circle c12( VecPosition( 40, 3 ), 40 );
01633   Circle c21( VecPosition(  0,0 ), 5);
01634   Circle c22( VecPosition(  3,0 ), 40 );
01635 
01636   VecPosition p1, p2;
01637 
01638   cout << c11.getIntersectionArea( c21 ) << endl;
01639   cout << c12.getIntersectionArea( c21 ) << endl;
01640   cout << c22.getIntersectionArea( c11 ) << endl;
01641   cout << c12.getIntersectionArea( c22 ) << endl;
01642   return 0;
01643 }
01644 
01645 int main( void )
01646 {
01647   cout << getBisectorTwoAngles( -155.3, 179.0 ) << endl;
01648   cout << getBisectorTwoAngles( -179.3, 179.0 ) << endl;
01649 }
01650 */

Generated on Thu Mar 7 00:37:42 2002 for UvA Trilearn 2001 by doxygen1.2.12 written by Dimitri van Heesch, © 1997-2001