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-2002, 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 */
00054 #include "Geometry.h"
00055 #include <stdio.h>    // needed for sprintf
00056 
00061 int sign( double d1 )
00062 {
00063   return (d1>0)?1:-1;
00064 }
00065 
00070 double max( double d1, double d2 )
00071 {
00072   return (d1>d2)?d1:d2;
00073 }
00074 
00079 double min( double d1, double d2 )
00080 {
00081   return (d1<d2)?d1:d2;
00082 }
00083 
00084 
00089 AngDeg Rad2Deg( AngRad x )
00090 {
00091   return ( x * 180 / M_PI );
00092 }
00093 
00098 AngRad Deg2Rad( AngDeg x )
00099 {
00100   return ( x * M_PI / 180 );
00101 }
00102 
00107 double cosDeg( AngDeg x )
00108 {
00109   return ( cos( Deg2Rad( x ) ) );
00110 }
00111 
00116 double sinDeg( AngDeg x )
00117 {
00118   return ( sin( Deg2Rad( x ) ) );
00119 }
00120 
00125 double tanDeg( AngDeg x )
00126 {
00127   return ( tan( Deg2Rad( x ) ) );
00128 }
00129 
00134 AngDeg atanDeg( double x )
00135 {
00136   return ( Rad2Deg( atan( x ) ) );
00137 }
00138 
00147 double atan2Deg( double x, double y )
00148 {
00149   if( fabs( x ) < EPSILON && fabs( y ) < EPSILON )
00150     return ( 0.0 );
00151 
00152   return ( Rad2Deg( atan2( x, y ) ) );
00153 }
00154 
00159 AngDeg acosDeg( double x )
00160 {
00161   if( x >= 1 )
00162     return ( 0.0 );
00163   else if( x <= -1 )
00164     return ( 180.0 );
00165 
00166   return ( Rad2Deg( acos( x ) ) );
00167 }
00168 
00173 AngDeg asinDeg( double x )
00174 {
00175   if( x >= 1 )
00176     return ( 90.0 );
00177   else if ( x <= -1 )
00178     return ( -90.0 );
00179 
00180   return ( Rad2Deg( asin( x ) ) );
00181 }
00182 
00191 bool isAngInInterval( AngDeg ang, AngDeg angMin, AngDeg angMax )
00192 {
00193   // convert all angles to interval 0..360
00194   if( ( ang    + 360 ) < 360 ) ang    += 360;
00195   if( ( angMin + 360 ) < 360 ) angMin += 360;
00196   if( ( angMax + 360 ) < 360 ) angMax += 360;
00197 
00198   if( angMin < angMax ) // 0 ---false-- angMin ---true-----angMax---false--360
00199     return angMin < ang && ang < angMax ;
00200   else                  // 0 ---true--- angMax ---false----angMin---true---360
00201     return !( angMax < ang && ang < angMin );
00202 }
00203 
00210 AngDeg getBisectorTwoAngles( AngDeg angMin, AngDeg angMax )
00211 {
00212   // separate sine and cosine part to circumvent boundary problem
00213   return VecPosition::normalizeAngle(
00214             atan2Deg( (sinDeg( angMin) + sinDeg( angMax ) )/2.0,
00215                       (cosDeg( angMin) + cosDeg( angMax ) )/2.0 ) );
00216 }
00217 
00218 /******************************************************************************/
00219 /********************   CLASS VECPOSITION   ***********************************/
00220 /******************************************************************************/
00221 
00235 VecPosition::VecPosition( double x, double y, CoordSystemT cs )
00236 {
00237   setVecPosition( x, y, cs );
00238 }
00239 
00244 VecPosition VecPosition::operator - ( )
00245 {
00246   return ( VecPosition( -m_x, -m_y ) );
00247 }
00248 
00257 VecPosition VecPosition::operator + ( const double &d )
00258 {
00259   return ( VecPosition( m_x + d, m_y + d ) );
00260 }
00261 
00267 VecPosition VecPosition::operator + ( const VecPosition &p )
00268 {
00269   return ( VecPosition( m_x + p.m_x, m_y + p.m_y ) );
00270 }
00271 
00280 VecPosition VecPosition::operator - ( const double &d )
00281 {
00282   return ( VecPosition( m_x - d, m_y - d ) );
00283 }
00284 
00292 VecPosition VecPosition::operator - ( const VecPosition &p )
00293 {
00294   return ( VecPosition( m_x - p.m_x, m_y - p.m_y ) );
00295 }
00296 
00304 VecPosition VecPosition::operator * ( const double &d  )
00305 {
00306   return ( VecPosition( m_x * d, m_y * d  ) );
00307 }
00308 
00315 VecPosition VecPosition::operator * ( const VecPosition &p )
00316 {
00317   return ( VecPosition( m_x * p.m_x, m_y * p.m_y ) );
00318 }
00319 
00326 VecPosition VecPosition::operator / ( const double &d )
00327 {
00328   return ( VecPosition( m_x / d, m_y / d  ) );
00329 }
00330 
00336 VecPosition VecPosition::operator / ( const VecPosition &p )
00337 {
00338   return ( VecPosition( m_x / p.m_x, m_y / p.m_y ) );
00339 }
00340 
00346 void VecPosition::operator = ( const double &d )
00347 {
00348   m_x = d;
00349   m_y = d;
00350 }
00351 
00357 void VecPosition::operator +=( const VecPosition &p )
00358 {
00359   m_x += p.m_x;
00360   m_y += p.m_y;
00361 }
00362 
00369 void VecPosition::operator += ( const double &d )
00370 {
00371   m_x += d;
00372   m_y += d;
00373 }
00374 
00381 void VecPosition::operator -=( const VecPosition &p )
00382 {
00383   m_x -= p.m_x;
00384   m_y -= p.m_y;
00385 }
00386 
00393 void VecPosition::operator -=( const double &d )
00394 {
00395   m_x -= d;
00396   m_y -= d;
00397 }
00398 
00405 void VecPosition::operator *=( const VecPosition &p )
00406 {
00407   m_x *= p.m_x;
00408   m_y *= p.m_y;
00409 }
00410 
00417 void VecPosition::operator *=( const double &d )
00418 {
00419   m_x *= d;
00420   m_y *= d;
00421 }
00422 
00428 void VecPosition::operator /=( const VecPosition &p )
00429 {
00430   m_x /= p.m_x;
00431   m_y /= p.m_y;
00432 }
00433 
00440 void VecPosition::operator /=( const double &d )
00441 {
00442   m_x /= d;
00443   m_y /= d;
00444 }
00445 
00452 bool VecPosition::operator !=( const VecPosition &p )
00453 {
00454   return ( ( m_x != p.m_x ) || ( m_y != p.m_y ) );
00455 }
00456 
00464 bool VecPosition::operator !=( const double &d )
00465 {
00466   return ( ( m_x != d ) || ( m_y != d ) );
00467 }
00468 
00475 bool VecPosition::operator ==( const VecPosition &p )
00476 {
00477   return ( ( m_x == p.m_x ) && ( m_y == p.m_y ) );
00478 }
00479 
00487 bool VecPosition::operator ==( const double &d )
00488 {
00489   return ( ( m_x == d ) && ( m_y == d ) );
00490 }
00491 
00499 ostream& operator <<( ostream &os, VecPosition v )
00500 {
00501   return ( os << "( " << v.m_x << ", " << v.m_y << " )" );
00502 }
00503 
00508 void VecPosition::show( CoordSystemT cs )
00509 {
00510   if( cs == CARTESIAN )
00511     cout << *this << endl;
00512   else
00513     cout << "( r: " << getMagnitude( ) << ", phi: " << getDirection( ) << "  )";
00514 }
00515 
00522 string VecPosition::str( CoordSystemT cs )
00523 {
00524   char buf[ 1024 ];
00525 
00526   if( cs == CARTESIAN )
00527     sprintf( buf, "( %f, %f )", getX( ), getY( ) );
00528   else
00529     sprintf( buf, "( r: %f, phi: %f )", getMagnitude( ), getDirection( ) );
00530 
00531   string str( buf );
00532   return ( str );
00533 }
00534 
00538 bool VecPosition::setX( double dX )
00539 {
00540   m_x = dX;
00541   return ( true );
00542 }
00543 
00546 double VecPosition::getX( ) const
00547 {
00548   return ( m_x );
00549 }
00550 
00554 bool VecPosition::setY( double dY )
00555 {
00556   m_y = dY;
00557   return ( true );
00558 }
00559 
00562 double VecPosition::getY( ) const
00563 {
00564   return ( m_y );
00565 }
00566 
00576 void VecPosition::setVecPosition( double dX = 0, double dY = 0, CoordSystemT cs)
00577 {
00578   if( cs == CARTESIAN )
00579   {
00580     m_x = dX;
00581     m_y = dY;
00582   }
00583   else
00584     *this = getVecPositionFromPolar( dX, dY );
00585 }
00586 
00593 double VecPosition::getDistanceTo( const VecPosition p )
00594 {
00595   return ( ( *this - p ).getMagnitude( ) );
00596 }
00597 
00606 VecPosition VecPosition::setMagnitude( double d )
00607 {
00608   if( getMagnitude( ) > EPSILON )
00609      ( *this ) *= ( d / getMagnitude( ) );
00610 
00611   return ( *this );
00612 }
00613 
00618 double VecPosition::getMagnitude( ) const
00619 {
00620   return ( sqrt( m_x * m_x + m_y * m_y ) );
00621 }
00622 
00629 AngDeg VecPosition::getDirection( ) const
00630 {
00631   return ( atan2Deg( m_y, m_x ) );
00632 }
00633 
00640 bool VecPosition::isInFrontOf( const VecPosition &p )
00641 {
00642   return ( ( m_x > p.getX( ) ) ? true : false );
00643 }
00644 
00650 bool VecPosition::isInFrontOf( const double &d )
00651 {
00652   return ( ( m_x > d ) ? true : false );
00653 }
00654 
00661 bool VecPosition::isBehindOf( const VecPosition &p )
00662 {
00663   return ( ( m_x < p.getX( ) ) ? true : false );
00664 }
00665 
00671 bool VecPosition::isBehindOf( const double &d )
00672 {
00673   return ( ( m_x < d ) ? true : false );
00674 }
00675 
00682 bool VecPosition::isLeftOf( const VecPosition &p )
00683 {
00684   return ( ( m_y < p.getY( ) ) ? true : false );
00685 }
00686 
00692 bool VecPosition::isLeftOf( const double &d )
00693 {
00694   return ( ( m_y < d ) ? true : false );
00695 }
00696 
00703 bool VecPosition::isRightOf( const VecPosition &p )
00704 {
00705   return ( ( m_y > p.getY( ) ) ? true : false );
00706 }
00707 
00713 bool VecPosition::isRightOf( const double &d )
00714 {
00715   return ( ( m_y > d ) ? true : false );
00716 }
00717 
00725 bool VecPosition::isBetweenX( const VecPosition &p1, const VecPosition &p2 )
00726 {
00727   return ( ( isInFrontOf( p1 ) && isBehindOf( p2 ) ) ? true : false );
00728 }
00729 
00737 bool VecPosition::isBetweenX( const double &d1, const double &d2 )
00738 {
00739   return ( ( isInFrontOf( d1 ) && isBehindOf( d2 ) ) ? true : false );
00740 }
00741 
00750 bool VecPosition::isBetweenY( const VecPosition &p1, const VecPosition &p2 )
00751 {
00752   return ( ( isRightOf( p1 ) && isLeftOf( p2 ) ) ? true : false );
00753 }
00754 
00763 bool VecPosition::isBetweenY( const double &d1, const double &d2 )
00764 {
00765   return ( ( isRightOf( d1 ) && isLeftOf( d2 ) ) ? true : false );
00766 }
00767 
00772 VecPosition VecPosition::normalize( )
00773 {
00774   return ( setMagnitude( 1.0 ) );
00775 }
00776 
00787 VecPosition VecPosition::rotate( AngDeg angle )
00788 {
00789   // determine the polar representation of the current VecPosition
00790   double dMag    = this->getMagnitude( );
00791   double dNewDir = this->getDirection( ) + angle;  // add rotation angle to phi
00792   setVecPosition( dMag, dNewDir, POLAR );          // convert back to Cartesian
00793   return ( *this );
00794 }
00795 
00808 VecPosition VecPosition::globalToRelative( VecPosition origin, AngDeg ang )
00809 {
00810   // convert global coordinates into relative coordinates by aligning relative
00811   // frame and world frame. First perform translation to make origins of both
00812   // frames coincide. Then perform rotation to make axes of both frames coincide
00813   // (use negative angle since you rotate relative frame to world frame).
00814   *this -= origin;
00815   return ( rotate( -ang ) );
00816 }
00817 
00830 VecPosition VecPosition::relativeToGlobal( VecPosition origin, AngDeg ang )
00831 {
00832   // convert relative coordinates into global coordinates by aligning world
00833   // frame and relative frame. First perform rotation to make axes of both
00834   // frames coincide (use positive angle since you rotate world frame to
00835   // relative frame). Then perform translation to make origins of both frames
00836   // coincide.
00837   rotate( ang );
00838   *this += origin;
00839   return ( *this );
00840 }
00841 
00851 VecPosition VecPosition::getVecPositionOnLineFraction( VecPosition &p,
00852                                                        double      dFrac )
00853 {
00854   // determine point on line that lies at fraction dFrac of whole line
00855   // example: this --- 0.25 ---------  p
00856   // formula: this + dFrac * ( p - this ) = this - dFrac * this + dFrac * p =
00857   //          ( 1 - dFrac ) * this + dFrac * p
00858   return ( ( *this ) * ( 1.0 - dFrac ) + ( p * dFrac ) );
00859 }
00860 
00869 VecPosition VecPosition::getVecPositionFromPolar( double dMag, AngDeg ang )
00870 {
00871   // cos(phi) = x/r <=> x = r*cos(phi); sin(phi) = y/r <=> y = r*sin(phi)
00872   return ( VecPosition( dMag * cosDeg( ang ), dMag * sinDeg( ang ) ) );
00873 }
00874 
00879 AngDeg VecPosition::normalizeAngle( AngDeg angle )
00880 {
00881   while( angle > 180.0  ) angle -= 360.0;
00882   while( angle < -180.0 ) angle += 360.0;
00883 
00884   return ( angle );
00885 }
00886 
00887 
00888 /******************************************************************************/
00889 /*********************** CLASS GEOMETRY ***************************************/
00890 /******************************************************************************/
00891 
00902 double Geometry::getLengthGeomSeries( double dFirst, double dRatio, double dSum )
00903 {
00904   if( dRatio < 0 )
00905     cerr << "(Geometry:getLengthGeomSeries): negative ratio" << endl;
00906 
00907   // s = a + ar + ar^2 + .. + ar^n-1 and thus sr = ar + ar^2 + .. + ar^n
00908   // subtract: sr - s = - a + ar^n) =>  s(1-r)/a + 1 = r^n = temp
00909   // log r^n / n = n log r / log r = n = length
00910   double temp = (dSum * ( dRatio - 1 ) / dFirst) + 1;
00911   if( temp <= 0 )
00912     return -1.0;
00913   return log( temp ) / log( dRatio ) ;
00914 }
00915 
00926 double Geometry::getSumGeomSeries( double dFirst, double dRatio, double dLength)
00927 {
00928   // s = a + ar + ar^2 + .. + ar^n-1 and thus sr = ar + ar^2 + .. + ar^n
00929   // subtract: s - sr = a - ar^n) =>  s = a(1-r^n)/(1-r)
00930   return dFirst * ( 1 - pow( dRatio, dLength ) ) / ( 1 - dRatio ) ;
00931 }
00932 
00943 double Geometry::getSumInfGeomSeries( double dFirst, double dRatio )
00944 {
00945   if( dRatio > 1 )
00946     cerr << "(Geometry:CalcLengthGeomSeries): series does not converge" << endl;
00947 
00948   // s = a(1-r^n)/(1-r) with n->inf and 0<r<1 => r^n = 0
00949   return dFirst / ( 1 - dRatio );
00950 }
00951 
00962 double Geometry::getFirstGeomSeries( double dSum, double dRatio, double dLength)
00963 {
00964   // s = a + ar + ar^2 + .. + ar^n-1 and thus sr = ar + ar^2 + .. + ar^n
00965   // subtract: s - sr = a - ar^n) =>  s = a(1-r^n)/(1-r) => a = s*(1-r)/(1-r^n)
00966   return dSum *  ( 1 - dRatio )/( 1 - pow( dRatio, dLength ) ) ;
00967 }
00968 
00979 double Geometry::getFirstInfGeomSeries( double dSum, double dRatio )
00980 {
00981   if( dRatio > 1 )
00982     cerr << "(Geometry:getFirstInfGeomSeries):series does not converge" << endl;
00983 
00984   // s = a(1-r^n)/(1-r) with r->inf and 0<r<1 => r^n = 0 => a = s ( 1 - r)
00985   return dSum * ( 1 - dRatio );
00986 }
00987 
00997 int Geometry::abcFormula(double a, double b, double c, double *s1, double *s2)
00998 {
00999   double dDiscr = b*b - 4*a*c;       // discriminant is b^2 - 4*a*c
01000   if (fabs(dDiscr) < EPSILON )       // if discriminant = 0
01001   {
01002     *s1 = -b / (2 * a);              //  only one solution
01003     return 1;
01004   }
01005   else if (dDiscr < 0)               // if discriminant < 0
01006     return 0;                        //  no solutions
01007   else                               // if discriminant > 0
01008   {
01009     dDiscr = sqrt(dDiscr);           //  two solutions
01010     *s1 = (-b + dDiscr ) / (2 * a);
01011     *s2 = (-b - dDiscr ) / (2 * a);
01012     return 2;
01013   }
01014 }
01015 
01016 /******************************************************************************/
01017 /********************** CLASS CIRCLE ******************************************/
01018 /******************************************************************************/
01019 
01024 Circle::Circle( VecPosition pos, double dR )
01025 {
01026   setCircle( pos, dR );
01027 }
01028 
01031 Circle::Circle( )
01032 {
01033   setCircle( VecPosition(-1000.0,-1000.0), 0);
01034 }
01035 
01040 void Circle::show( ostream& os)
01041 {
01042   os << "c:" << m_posCenter << ", r:" << m_dRadius;
01043 }
01044 
01050 bool Circle::setCircle( VecPosition pos, double dR )
01051 {
01052   setCenter( pos );
01053   return setRadius( dR  );
01054 }
01058 bool Circle::setRadius( double dR )
01059 {
01060   if( dR > 0 )
01061   {
01062     m_dRadius = dR;
01063     return true;
01064   }
01065   else
01066   {
01067     m_dRadius = 0.0;
01068     return false;
01069   }
01070 }
01071 
01074 double Circle::getRadius()
01075 {
01076   return m_dRadius;
01077 }
01078 
01082 bool Circle::setCenter( VecPosition pos )
01083 {
01084   m_posCenter = pos;
01085   return true;
01086 }
01087 
01090 VecPosition Circle::getCenter()
01091 {
01092   return m_posCenter;
01093 }
01094 
01097 double Circle::getCircumference()
01098 {
01099   return 2.0*M_PI*getRadius();
01100 }
01101 
01104 double Circle::getArea()
01105 {
01106   return M_PI*getRadius()*getRadius();
01107 }
01108 
01114 bool Circle::isInside( VecPosition pos )
01115 {
01116   return m_posCenter.getDistanceTo( pos ) < getRadius() ;
01117 }
01124 int Circle::getIntersectionPoints( Circle c, VecPosition *p1, VecPosition *p2)
01125 {
01126     double x0, y0, r0;
01127     double x1, y1, r1;
01128 
01129     x0 = getCenter( ).getX();
01130     y0 = getCenter( ).getY();
01131     r0 = getRadius( );
01132     x1 = c.getCenter( ).getX();
01133     y1 = c.getCenter( ).getY();
01134     r1 = c.getRadius( );
01135 
01136     double      d, dx, dy, h, a, x, y, p2_x, p2_y;
01137 
01138     // first calculate distance between two centers circles P0 and P1.
01139     dx = x1 - x0;
01140     dy = y1 - y0;
01141     d = sqrt(dx*dx + dy*dy);
01142 
01143     // normalize differences
01144     dx /= d; dy /= d;
01145 
01146     // a is distance between p0 and point that is the intersection point P2
01147     // that intersects P0-P1 and the line that crosses the two intersection
01148     // points P3 and P4.
01149     // Define two triangles: P0,P2,P3 and P1,P2,P3.
01150     // with distances a, h, r0 and b, h, r1 with d = a + b
01151     // We know a^2 + h^2 = r0^2 and b^2 + h^2 = r1^2 which then gives
01152     // a^2 + r1^2 - b^2 = r0^2 with d = a + b ==> a^2 + r1^2 - (d-a)^2 = r0^2
01153     // ==> r0^2 + d^2 - r1^2 / 2*d
01154     a = (r0*r0 + d*d - r1*r1) / (2.0 * d);
01155 
01156     // h is then a^2 + h^2 = r0^2 ==> h = sqrt( r0^2 - a^2 )
01157     double      arg = r0*r0 - a*a;
01158     h = (arg > 0.0) ? sqrt(arg) : 0.0;
01159 
01160     // First calculate P2
01161     p2_x = x0 + a * dx;
01162     p2_y = y0 + a * dy;
01163 
01164     // and finally the two intersection points
01165     x =  p2_x - h * dy;
01166     y =  p2_y + h * dx;
01167     p1->setVecPosition( x, y );
01168     x =  p2_x + h * dy;
01169     y =  p2_y - h * dx;
01170     p2->setVecPosition( x, y );
01171 
01172     return (arg < 0.0) ? 0 : ((arg == 0.0 ) ? 1 :  2);
01173 }
01174 
01178 double Circle::getIntersectionArea( Circle c )
01179 {
01180   VecPosition pos1, pos2, pos3;
01181   double d, h, dArea;
01182   AngDeg ang;
01183 
01184   d = getCenter().getDistanceTo( c.getCenter() ); // dist between two centers
01185   if( d > c.getRadius() + getRadius() )           // larger than sum radii
01186     return 0.0;                                   // circles do not intersect
01187   if( d <= fabs(c.getRadius() - getRadius() ) )   // one totally in the other
01188   {
01189     double dR = min( c.getRadius(), getRadius() );// return area smallest circle
01190     return M_PI*dR*dR;
01191   }
01192 
01193   int iNrSol = getIntersectionPoints( c, &pos1, &pos2 );
01194   if( iNrSol != 2 )
01195     return 0.0;
01196 
01197   // the intersection area of two circles can be divided into two segments:
01198   // left and right of the line between the two intersection points p1 and p2.
01199   // The outside area of each segment can be calculated by taking the part
01200   // of the circle pie excluding the triangle from the center to the
01201   // two intersection points.
01202   // The pie equals pi*r^2 * rad(2*ang) / 2*pi = 0.5*rad(2*ang)*r^2 with ang
01203   // the angle between the center c of the circle and one of the two
01204   // intersection points. Thus the angle between c and p1 and c and p3 where
01205   // p3 is the point that lies halfway between p1 and p2.
01206   // This can be calculated using ang = asin( d / r ) with d the distance
01207   // between p1 and p3 and r the radius of the circle.
01208   // The area of the triangle is 2*0.5*h*d.
01209 
01210   pos3 = pos1.getVecPositionOnLineFraction( pos2, 0.5 );
01211   d = pos1.getDistanceTo( pos3 );
01212   h = pos3.getDistanceTo( getCenter() );
01213   ang = asin( d / getRadius() );
01214 
01215   dArea = ang*getRadius()*getRadius();
01216   dArea = dArea - d*h;
01217 
01218   // and now for the other segment the same story
01219   h = pos3.getDistanceTo( c.getCenter() );
01220   ang = asin( d / c.getRadius() );
01221   dArea = dArea + ang*c.getRadius()*c.getRadius();
01222   dArea = dArea - d*h;
01223 
01224   return dArea;
01225 }
01226 
01227 
01228 /******************************************************************************/
01229 /***********************  CLASS LINE *******************************************/
01230 /******************************************************************************/
01231 
01237 Line::Line( double dA, double dB, double dC )
01238 {
01239   m_a = dA;
01240   m_b = dB;
01241   m_c = dC;
01242 }
01243 
01249 ostream& operator <<(ostream & os, Line l)
01250 {
01251   double a = l.getACoefficient();
01252   double b = l.getBCoefficient();
01253   double c = l.getCCoefficient();
01254 
01255   // ay + bx + c = 0 -> y = -b/a x - c/a
01256   if( a == 0 )
01257     os << "x = " << -c/b;
01258   else
01259   {
01260     os << "y = ";
01261     if( b != 0 )
01262       os << -b/a << "x ";
01263     if( c > 0 )
01264        os << "- " <<  fabs(c/a);
01265     else if( c < 0 )
01266        os << "+ " <<  fabs(c/a);
01267   }
01268   return os;
01269 }
01270 
01273 void Line::show( ostream& os)
01274 {
01275   os << *this;
01276 }
01277 
01282 VecPosition Line::getIntersection( Line line )
01283 {
01284   VecPosition pos;
01285   double x, y;
01286 
01287   if( m_b == line.getBCoefficient() ) // lines are parallel, no intersection
01288   {
01289     return pos;
01290   }
01291   if( m_a == 0 )               // bx + c = 0 and a2*y + b2*x + c2 = 0 ==> x = -c/b
01292   {                          // calculate x using the current line
01293     x = -m_c/m_b;                // and calculate the y using the second line
01294     y = line.getYGivenX(x);
01295   }
01296   else if( line.getACoefficient() == 0 )
01297   {                         // ay + bx + c = 0 and b2*x + c2 = 0 ==> x = -c2/b2
01298    x = -line.getCCoefficient()/line.getBCoefficient(); // calculate x using
01299    y = getYGivenX(x);       // 2nd line and calculate y using current line
01300   }
01301   // ay + bx + c = 0 and a2y + b2*x + c2 = 0
01302   // y = (-b2/a2)x - c2/a2
01303   // bx = -a*y - c =>  bx = -a*(-b2/a2)x -a*(-c2/a2) - c ==>
01304   // ==> a2*bx = a*b2*x + a*c2 - a2*c ==> x = (a*c2 - a2*c)/(a2*b - a*b2)
01305   // calculate x using the above formula and the y using the current line
01306   else
01307   {
01308     x = (m_a*line.getCCoefficient() - line.getACoefficient()*m_c)/
01309                     (line.getACoefficient()*m_b - m_a*line.getBCoefficient());
01310     y = getYGivenX(x);
01311   }
01312 
01313   return VecPosition( x, y );
01314 }
01315 
01316 
01324 int Line::getCircleIntersectionPoints( Circle circle,
01325               VecPosition *posSolution1, VecPosition *posSolution2 )
01326 {
01327   int    iSol;
01328   double dSol1, dSol2;
01329   double h = circle.getCenter().getX();
01330   double k = circle.getCenter().getY();
01331 
01332   // line:   x = -c/b (if a = 0)
01333   // circle: (x-h)^2 + (y-k)^2 = r^2, with h = center.x and k = center.y
01334   // fill in:(-c/b-h)^2 + y^2 -2ky + k^2 - r^2 = 0
01335   //         y^2 -2ky + (-c/b-h)^2 + k^2 - r^2 = 0
01336   // and determine solutions for y using abc-formula
01337   if( fabs(m_a) < EPSILON )
01338   {
01339     iSol = Geometry::abcFormula( 1, -2*k, ((-m_c/m_b) - h)*((-m_c/m_b) - h)
01340               + k*k - circle.getRadius()*circle.getRadius(), &dSol1, &dSol2);
01341     posSolution1->setVecPosition( (-m_c/m_b), dSol1 );
01342     posSolution2->setVecPosition( (-m_c/m_b), dSol2 );
01343     return iSol;
01344   }
01345 
01346   // ay + bx + c = 0 => y = -b/a x - c/a, with da = -b/a and db = -c/a
01347   // circle: (x-h)^2 + (y-k)^2 = r^2, with h = center.x and k = center.y
01348   // fill in:x^2 -2hx + h^2 + (da*x-db)^2 -2k(da*x-db) + k^2 - r^2 = 0
01349   //         x^2 -2hx + h^2 + da^2*x^2 + 2da*db*x + db^2 -2k*da*x -2k*db
01350   //                                                         + k^2 - r^2 = 0
01351   //         (1+da^2)*x^2 + 2(da*db-h-k*da)*x + h2 + db^2  -2k*db + k^2 - r^2 = 0
01352   // and determine solutions for x using abc-formula
01353   // fill in x in original line equation to get y coordinate
01354   double da = -m_b/m_a;
01355   double db = -m_c/m_a;
01356 
01357   double dA = 1 + da*da;
01358   double dB = 2*( da*db - h - k*da );
01359   double dC = h*h + db*db - 2*k*db + k*k - circle.getRadius()*circle.getRadius();
01360 
01361   iSol = Geometry::abcFormula( dA, dB, dC, &dSol1, &dSol2 );
01362 
01363   posSolution1->setVecPosition( dSol1, da*dSol1 + db );
01364   posSolution2->setVecPosition( dSol2, da*dSol2 + db );
01365   return iSol;
01366 
01367 }
01368 
01374 Line Line::getTangentLine( VecPosition pos )
01375 {
01376   // ay + bx + c = 0 -> y = (-b/a)x + (-c/a)
01377   // tangent: y = (a/b)*x + C1 -> by - ax + C2 = 0 => C2 = ax - by
01378   // with pos.y = y, pos.x = x
01379   return Line( m_b, -m_a, m_a*pos.getX() - m_b*pos.getY() );
01380 }
01381 
01385 VecPosition Line::getPointOnLineClosestTo( VecPosition pos )
01386 {
01387   Line l2 = getTangentLine( pos );  // get tangent line
01388   return getIntersection( l2 );     // and intersection between the two lines
01389 }
01390 
01395 double Line::getDistanceWithPoint( VecPosition pos )
01396 {
01397   return pos.getDistanceTo( getPointOnLineClosestTo( pos ) );
01398 }
01399 
01407 bool Line::isInBetween( VecPosition pos, VecPosition point1, VecPosition point2)
01408 {
01409   pos          = getPointOnLineClosestTo( pos ); // get closest point
01410   double dDist = point1.getDistanceTo( point2 ); // get distance between 2 pos
01411 
01412   // if the distance from both points to the projection is smaller than this
01413   // dist, the pos lies in between.
01414   return pos.getDistanceTo( point1 ) <= dDist &&
01415          pos.getDistanceTo( point2 ) <= dDist;
01416 }
01417 
01421 double Line::getYGivenX( double x )
01422 {
01423  if( m_a == 0 )
01424  {
01425    cerr << "(Line::getYGivenX) Cannot calculate Y coordinate: " ;
01426    show( cerr );
01427    cerr << endl;
01428    return 0;
01429  }
01430   // ay + bx + c = 0 ==> ay = -(b*x + c)/a
01431   return -(m_b*x+m_c)/m_a;
01432 }
01433 
01437 double Line::getXGivenY( double y )
01438 {
01439  if( m_b == 0 )
01440  {
01441    cerr << "(Line::getXGivenY) Cannot calculate X coordinate\n" ;
01442    return 0;
01443  }
01444   // ay + bx + c = 0 ==> bx = -(a*y + c)/a
01445   return -(m_a*y+m_c)/m_b;
01446 }
01447 
01452 Line Line::makeLineFromTwoPoints( VecPosition pos1, VecPosition pos2 )
01453 {
01454   // 1*y + bx + c = 0 => y = -bx - c
01455   // with -b the direction coefficient (or slope)
01456   // and c = - y - bx
01457   double dA=1.0, dB, dC;
01458   double dTemp = pos2.getX() - pos1.getX(); // determine the slope
01459   if( fabs(dTemp) < EPSILON )
01460   {
01461     // ay + bx + c = 0 with vertical slope=> a = 0, b = 1
01462     dA = 0.0;
01463     dB = 1.0;
01464   }
01465   else
01466   {
01467     // y = (-b)x -c with -b the slope of the line
01468     dA = 1.0;
01469     dB = -(pos2.getY() - pos1.getY())/dTemp;
01470   }
01471   // ay + bx + c = 0 ==> c = -a*y - b*x
01472   dC =  - dA*pos2.getY()  - dB * pos2.getX();
01473   return Line( dA, dB, dC );
01474 }
01475 
01480 Line Line::makeLineFromPositionAndAngle( VecPosition vec, AngDeg angle )
01481 {
01482   // calculate point somewhat further in direction 'angle' and make
01483   // line from these two points.
01484   return makeLineFromTwoPoints( vec, vec+VecPosition(1,angle,POLAR));
01485 }
01486 
01489 double Line::getACoefficient() const
01490 {
01491   return m_a;
01492 }
01493 
01496 double Line::getBCoefficient() const
01497 {
01498  return m_b;
01499 }
01500 
01503 double Line::getCCoefficient() const
01504 {
01505  return m_c;
01506 }
01507 
01508 /******************************************************************************/
01509 /********************** CLASS RECTANGLE ***************************************/
01510 /******************************************************************************/
01511 
01518 Rectangle::Rectangle( VecPosition pos, VecPosition pos2 )
01519 {
01520   setRectanglePoints( pos, pos2 );
01521 }
01522 
01527 void Rectangle::setRectanglePoints( VecPosition pos1, VecPosition pos2 )
01528 {
01529   m_posLeftTop.setX    ( max( pos1.getX(), pos2.getX() ) );
01530   m_posLeftTop.setY    ( min( pos1.getY(), pos2.getY() ) );
01531   m_posRightBottom.setX( min( pos1.getX(), pos2.getX() ) );
01532   m_posRightBottom.setY( max( pos1.getY(), pos2.getY() ) );
01533 }
01534 
01538 void Rectangle::show( ostream& os )
01539 {
01540   cout << "rect(" << m_posLeftTop << " " << m_posRightBottom << ")";
01541 }
01542 
01547 bool Rectangle::isInside( VecPosition pos )
01548 {
01549   return pos.isBetweenX( m_posRightBottom.getX(), m_posLeftTop.getX() ) &&
01550          pos.isBetweenY( m_posLeftTop.getY(),     m_posRightBottom.getY() );
01551 
01552 }
01553 
01557 bool Rectangle::setPosLeftTop( VecPosition pos )
01558 {
01559   m_posLeftTop = pos;
01560   return true;
01561 }
01562 
01565 VecPosition Rectangle::getPosLeftTop( VecPosition pos )
01566 {
01567   return m_posLeftTop;
01568 }
01569 
01573 bool Rectangle::setPosRightBottom( VecPosition pos )
01574 {
01575   m_posRightBottom = pos;
01576   return true;
01577 }
01578 
01581 VecPosition Rectangle::getPosRightBottom( VecPosition pos )
01582 {
01583   return m_posRightBottom;
01584 }
01585 
01586 /******************************************************************************/
01587 /********************** TESTING PURPOSES *************************************/
01588 /******************************************************************************/
01589 
01590 /*
01591 #include<iostream.h>
01592 
01593 int main( void )
01594 {
01595   double dFirst = 1.0;
01596   double dRatio = 2.5;
01597   double dSum   = 63.4375;
01598   double dLength = 4.0;
01599 
01600   printf( "sum: %f\n", Geometry::getSumGeomSeries( dFirst, dRatio, dLength));
01601   printf( "length: %f\n", Geometry::getLengthGeomSeries( dFirst, dRatio, dSum));
01602 }
01603 
01604 int main( void )
01605 {
01606   Line l1(1,-1,3 );
01607   Line l2(1,-0.2,10 );
01608  Line l3 = Line::makeLineFromTwoPoints( VecPosition(1,-1), VecPosition(2,-2) );
01609  l3.show();
01610  cout << endl;
01611  l1.show();
01612  l2.show();
01613   l1.getIntersection( l2 ).show();
01614 }
01615 
01616 
01617 int main( void )
01618 {
01619   Line l( 1, -1, 0 );
01620   VecPosition s1, s2;
01621   int i = l.getCircleIntersectionPoints( Circle( VecPosition(1,1),1) &s1, &s2 );
01622   printf( "number of solutions: %d\n", i );
01623   if( i == 2 )
01624   {
01625     cout << s1 << " " << s2 ;
01626   }
01627   else if( i == 1 )
01628   {
01629     cout << s1;
01630   }
01631   cout << "line: " << l;
01632 }
01633 
01634 int main( void )
01635 {
01636   Circle c11( VecPosition( 10, 0 ), 10);
01637   Circle c12( VecPosition( 40, 3 ), 40 );
01638   Circle c21( VecPosition(  0,0 ), 5);
01639   Circle c22( VecPosition(  3,0 ), 40 );
01640 
01641   VecPosition p1, p2;
01642 
01643   cout << c11.getIntersectionArea( c21 ) << endl;
01644   cout << c12.getIntersectionArea( c21 ) << endl;
01645   cout << c22.getIntersectionArea( c11 ) << endl;
01646   cout << c12.getIntersectionArea( c22 ) << endl;
01647   return 0;
01648 }
01649 
01650 int main( void )
01651 {
01652   cout << getBisectorTwoAngles( -155.3, 179.0 ) << endl;
01653   cout << getBisectorTwoAngles( -179.3, 179.0 ) << endl;
01654 }
01655 */

Generated on Tue Jul 2 10:18:51 2002 for UvA Trilearn 2002 by doxygen1.2.12 written by Dimitri van Heesch, © 1997-2001