Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

Tools/Math/Geometry.cpp

Go to the documentation of this file.
00001 /**
00002 * @file Math/Geometry.cpp
00003 * Implemets class Geometry
00004 *
00005 * @author <A href=mailto:juengel@informatik.hu-berlin.de>Matthias Jüngel</A>
00006 * @author <a href="mailto:walter.nistico@uni-dortmund.de">Walter Nistico</a>
00007 */
00008 
00009 #include "Geometry.h"
00010 #include "Tools/FieldDimensions.h"
00011 #include "Tools/Debugging/Debugging.h"
00012 #include "Tools/RobotConfiguration.h"
00013 
00014 Geometry::Circle::Circle() : radius(0) 
00015 {
00016 }
00017 
00018 double Geometry::angleTo(const Pose2D& from, 
00019                                 const Vector2<double>& to)
00020 {
00021   Pose2D relPos = Pose2D(to) - from;
00022   return atan2(relPos.translation.y,relPos.translation.x);
00023 }
00024 
00025 double Geometry::distanceTo(const Pose2D& from, 
00026                                    const Vector2<double>& to)
00027 {
00028   return (Pose2D(to) - from).translation.abs();
00029 }
00030 
00031 Vector2<double> Geometry::vectorTo(const Pose2D& from, const Vector2<double>& to)
00032 {
00033   return (Pose2D(to) - from).translation;
00034 }
00035 
00036 void Geometry::Line::normalizeDirection()
00037 {
00038   double distance = 
00039     sqrt(sqr(direction.x) + sqr(direction.y));
00040   direction.x = direction.x / distance;
00041   direction.y = direction.y / distance;
00042 }
00043 
00044 Geometry::Circle Geometry::getCircle
00045 (
00046  const Vector2<int> point1,
00047  const Vector2<int> point2,
00048  const Vector2<int> point3
00049  )
00050 {
00051   double x1 = point1.x;
00052   double y1 = point1.y;
00053   double x2 = point2.x;
00054   double y2 = point2.y;
00055   double x3 = point3.x;
00056   double y3 = point3.y;
00057   
00058   Circle circle;
00059   
00060   if((x2*y1 - x3*y1 - x1*y2 + x3*y2 + x1*y3 - x2*y3 == 0) )
00061   {
00062     circle.radius = 0;
00063   }
00064   else
00065   {
00066     circle.radius =
00067       0.5 * 
00068       sqrt(
00069       ( (sqr(x1 - x2) + sqr(y1 - y2) ) *
00070       (sqr(x1 - x3) + sqr(y1 - y3) ) *
00071       (sqr(x2 - x3) + sqr(y2 - y3) )
00072       )
00073       /
00074       sqr(x2*y1 - x3*y1 - x1*y2 + x3*y2 + x1*y3 - x2*y3)
00075       );
00076   }
00077   
00078   if( (2 * (-x2*y1 + x3*y1 + x1*y2 - x3*y2 - x1*y3 + x2*y3) == 0) )
00079   {
00080     circle.center.x = 0;
00081   }
00082   else
00083   {
00084     circle.center.x =
00085       (
00086       sqr(x3) * (y1 - y2) + 
00087       (sqr(x1) + (y1 - y2) * (y1 - y3)) * (y2 - y3) +
00088       sqr(x2) * (-y1 + y3)
00089       )
00090       /
00091       (2 * (-x2*y1 + x3*y1 + x1*y2 - x3*y2 - x1*y3 + x2*y3) );
00092   }   
00093   
00094   if((2 * (x2*y1 - x3*y1 - x1*y2 + x3*y2 + x1*y3 - x2*y3) == 0) )
00095   {
00096     circle.center.y = 0;
00097   }
00098   else
00099   {
00100     circle.center.y =
00101       (
00102       sqr(x1) * (x2 - x3) + 
00103       sqr(x2) * x3 + 
00104       x3*(-sqr(y1) + sqr(y2) ) - 
00105       x2*(+sqr(x3) - sqr(y1) + sqr(y3) ) + 
00106       x1*(-sqr(x2) + sqr(x3) - sqr(y2) + sqr(y3) )
00107       )
00108       /
00109       (2 * (x2*y1 - x3*y1 - x1*y2 + x3*y2 + x1*y3 - x2*y3) );
00110   } 
00111   return circle;
00112 }
00113 
00114 bool Geometry::getIntersectionOfLines
00115 (
00116  const Line line1,
00117  const Line line2,
00118  Vector2<int>& intersection
00119  )
00120 {
00121  Vector2<double> intersectionDouble;
00122  bool toReturn = getIntersectionOfLines(line1,line2,intersectionDouble);
00123  intersection.x = (int)intersectionDouble.x;
00124  intersection.y = (int)intersectionDouble.y;
00125  return toReturn;
00126 }
00127 
00128 bool Geometry::getIntersectionOfLines
00129 (
00130  const Line line1,
00131  const Line line2,
00132  Vector2<double>& intersection
00133  )
00134 {
00135   if(line1.direction.y * line2.direction.x == line1.direction.x * line2.direction.y)
00136   {
00137     return false;
00138   }
00139   
00140   intersection.x = 
00141     line1.base.x +
00142     line1.direction.x * 
00143     (
00144     line1.base.y * line2.direction.x - 
00145     line2.base.y * line2.direction.x + 
00146     (-line1.base.x + line2.base.x) * line2.direction.y
00147     )
00148     /
00149     ( (-line1.direction.y) * line2.direction.x + line1.direction.x * line2.direction.y );
00150   
00151   intersection.y = 
00152     line1.base.y + 
00153     line1.direction.y *
00154     (
00155     -line1.base.y * line2.direction.x + 
00156     line2.base.y * line2.direction.x + 
00157     (line1.base.x - line2.base.x) * line2.direction.y
00158     )
00159     /
00160     (line1.direction.y * line2.direction.x - line1.direction.x * line2.direction.y);
00161   
00162   return true;
00163 }
00164 
00165 bool Geometry::getIntersectionOfRaysFactor
00166 (
00167  const Line ray1,
00168  const Line ray2,
00169  double& factor
00170  )
00171 {
00172   double divisor = ray2.direction.x * ray1.direction.y - ray1.direction.x * ray2.direction.y;
00173   if(divisor==0)
00174   {
00175     return false;
00176   }
00177   double k=(ray2.direction.y*ray1.base.x - ray2.direction.y*ray2.base.x - ray2.direction.x*ray1.base.y + ray2.direction.x*ray2.base.y)/divisor;
00178   double l=(ray1.direction.y*ray1.base.x - ray1.direction.y*ray2.base.x - ray1.direction.x*ray1.base.y + ray1.direction.x*ray2.base.y)/divisor;
00179   if ((k>=0)&&(l>=0)&&(k<=1)&&(l<=1))
00180   {
00181     //intersection=ray1.base + ray1.direction*k;
00182     factor=k;
00183     return true;
00184   }
00185   return false;
00186 }
00187 
00188 double Geometry::getDistanceToLine
00189 (
00190  const Line line,
00191  const Vector2<double>& point
00192  )
00193 {
00194   if (line.direction.x == 0 && line.direction.y == 0) 
00195     return distance(point, line.base);
00196 
00197   Vector2<double> normal;
00198   normal.x = line.direction.y;
00199   normal.y = -line.direction.x;
00200   normal.normalize();
00201 
00202   double c = normal * line.base;
00203 
00204   return normal * point - c;
00205 }
00206 
00207 double Geometry::getDistanceToEdge
00208 (
00209  const Line line,
00210  const Vector2<double>& point
00211  )
00212 {
00213   if (line.direction.x == 0 && line.direction.y == 0) 
00214     return distance(point, line.base);
00215 
00216   double c = line.direction * line.base;
00217 
00218   double d = (line.direction * point - c) / (line.direction * line.direction);
00219 
00220   if (d < 0) 
00221     return distance(point, line.base);
00222   else if (d > 1.0)
00223     return distance(point, line.base + line.direction);
00224   else
00225     return fabs(getDistanceToLine(line, point));
00226 }
00227 
00228 
00229 double Geometry::distance
00230 (
00231  const Vector2<double>& point1,
00232  const Vector2<double>& point2
00233  )
00234 {
00235   return (point2 - point1).abs();
00236 }
00237 
00238 double Geometry::distance
00239 (
00240  const Vector2<int>& point1,
00241  const Vector2<int>& point2
00242  )
00243 {
00244   return (point2 - point1).abs();
00245 }
00246 
00247 double Geometry::calculateScaleFactor(
00248   int y,
00249   unsigned long frameNumber,
00250   unsigned long prevFrameNumber,
00251   const CameraInfo& cameraInfo
00252   )
00253 {
00254   if(frameNumber != prevFrameNumber)
00255   {
00256     const RobotDimensions& r = getRobotConfiguration().getRobotDimensions();
00257     double timeDiff = (frameNumber - prevFrameNumber) * r.motionCycleTime; // in seconds
00258     double imageDiff = timeDiff * r.imagesPerSecond; // how many images are between the old and the current one (should be 1)?
00259     return (1 - double(1 + y) / cameraInfo.resolutionHeight) / imageDiff * 0.9; // interpolate, 10% less
00260   }
00261   else
00262     return 0;
00263 }
00264 
00265 Vector3<double> Geometry::rayFromCamera(
00266   int y,
00267   const CameraMatrix& cameraMatrix, 
00268   const CameraMatrix& prevCameraMatrix,
00269   const Vector3<double> vector,
00270   const CameraInfo& cameraInfo
00271   )
00272 {
00273   Vector3<double> v1 = cameraMatrix.rotation * vector;
00274   if(!cameraInfo.simulated)
00275   {
00276     Vector3<double> v2 = prevCameraMatrix.rotation * vector;
00277     // shift current percept towards old percept based on image row
00278     v1 += (v2 - v1) * calculateScaleFactor(y, cameraMatrix.frameNumber, prevCameraMatrix.frameNumber, cameraInfo);
00279   }
00280   return v1;
00281 }
00282 
00283 void Geometry::calculateAnglesForPoint
00284 (
00285  const Vector2<int>& point, 
00286  const CameraMatrix& cameraMatrix, 
00287  const CameraInfo& cameraInfo, 
00288  Vector2<double>& angles
00289  )
00290 {
00291   double factor = cameraInfo.focalLength;
00292   
00293   Vector3<double> vectorToPoint(
00294     factor,
00295     cameraInfo.opticalCenter.x - point.x,
00296     cameraInfo.opticalCenter.y - point.y);
00297   
00298   Vector3<double> vectorToPointWorld = 
00299     cameraMatrix.rotation * vectorToPoint;
00300   
00301   angles.x =
00302     atan2(vectorToPointWorld.y,vectorToPointWorld.x);
00303   
00304   angles.y =
00305     atan2(
00306     vectorToPointWorld.z,
00307     sqrt(sqr(vectorToPointWorld.x) + sqr(vectorToPointWorld.y)) 
00308     );
00309 }
00310 
00311 void Geometry::calculateAnglesForPoint
00312 (
00313  const Vector2<int>& point, 
00314  const CameraMatrix& cameraMatrix, 
00315  const CameraMatrix& prevCameraMatrix, 
00316  const CameraInfo& cameraInfo, 
00317  Vector2<double>& angles
00318  )
00319 {
00320   calculateAnglesForPoint(point, cameraMatrix, cameraInfo, angles);
00321   if(!cameraInfo.simulated)
00322   {
00323     Vector2<double> angles2;
00324     calculateAnglesForPoint(point, prevCameraMatrix, cameraInfo, angles2);
00325     // shift current percept towards old percept based on image row
00326     angles += (angles2 - angles) * calculateScaleFactor(point.y, cameraMatrix.frameNumber, prevCameraMatrix.frameNumber, cameraInfo);
00327   }
00328 }
00329   
00330 void Geometry::calculatePointByAngles
00331 (
00332  const Vector2<double>& angles,
00333  const CameraMatrix& cameraMatrix, 
00334  const CameraInfo& cameraInfo, 
00335  Vector2<int>& point
00336  )
00337 {
00338   Vector3<double> vectorToPointWorld, vectorToPoint;
00339   vectorToPointWorld.x = cos(angles.x);
00340   vectorToPointWorld.y = sin(angles.x);
00341   vectorToPointWorld.z = tan(angles.y);
00342   
00343   RotationMatrix rotationMatrix = cameraMatrix.rotation;
00344   vectorToPoint = rotationMatrix.invert() * vectorToPointWorld;
00345   
00346   double factor = cameraInfo.focalLength;
00347   
00348   double scale = factor / vectorToPoint.x;
00349   
00350   point.x = (int)(0.5 + cameraInfo.opticalCenter.x - vectorToPoint.y * scale);
00351   point.y = (int)(0.5 + cameraInfo.opticalCenter.y  - vectorToPoint.z * scale);
00352 }
00353 
00354 
00355 bool Geometry::clipLineWithQuadrangle
00356 (
00357  const Line lineToClip,
00358  const Vector2<double>& corner0, 
00359  const Vector2<double>& corner1,
00360  const Vector2<double>& corner2, 
00361  const Vector2<double>& corner3,
00362  Vector2<int>& clipPoint1, 
00363  Vector2<int>& clipPoint2
00364  )
00365 {
00366   Vector2<double> point1, point2;
00367   bool toReturn = clipLineWithQuadrangle(
00368    lineToClip,
00369    corner0, corner1, corner2, corner3,
00370    point1, point2);
00371    clipPoint1.x = (int)point1.x;
00372    clipPoint1.y = (int)point1.y;
00373    clipPoint2.x = (int)point2.x;
00374    clipPoint2.y = (int)point2.y;
00375    return toReturn;
00376 }
00377 
00378 bool Geometry::clipLineWithQuadrangle
00379 (
00380  const Line lineToClip,
00381  const Vector2<double>& corner0, 
00382  const Vector2<double>& corner1,
00383  const Vector2<double>& corner2, 
00384  const Vector2<double>& corner3,
00385  Vector2<double>& clipPoint1, 
00386  Vector2<double>& clipPoint2
00387  )
00388 {
00389   Geometry::Line side[4] , verticalLine;
00390 
00391   verticalLine.base = lineToClip.base;
00392 
00393   verticalLine.direction.x = -lineToClip.direction.y;
00394   verticalLine.direction.y = lineToClip.direction.x;
00395   
00396   Vector2<double> corner[4];
00397   corner[0] = corner0;
00398   corner[1] = corner1;
00399   corner[2] = corner2;
00400   corner[3] = corner3;
00401 
00402   side[0].base = corner0;
00403   side[0].direction = corner1;
00404   
00405   side[1].base = corner1;
00406   side[1].direction = corner3;
00407   
00408   side[2].base = corner2;
00409   side[2].direction = corner1;
00410   
00411   side[3].base = corner3;
00412   side[3].direction = corner3;
00413   
00414   Vector2<double> point1, point2, point;
00415   bool nextIsPoint1 = true;
00416   /*
00417   for(int i = 0; i < 4; i++)
00418   {
00419     if(Geometry::getIntersectionOfLines(side[i], lineToClip, point))
00420     {
00421       if(nextIsPoint1 && sign(point.x - corner[i]) != sign(point.x - corner[(i+1)%4])
00422         )
00423       {
00424         point1 = point;
00425         nextIsPoint1 = false;
00426       }
00427       else
00428         point2 = point;
00429     };
00430   }*/
00431 
00432   if(Geometry::getIntersectionOfLines(side[0], lineToClip, point))
00433   {
00434     if(corner[0].x < point.x && point.x < corner[1].x)
00435     {
00436       if(nextIsPoint1)
00437       {
00438         point1 = point;
00439         nextIsPoint1 = false;
00440       }
00441     }
00442   }
00443 
00444   if(Geometry::getIntersectionOfLines(side[1], lineToClip, point))
00445   {
00446     if(corner[1].y < point.y && point.y < corner[2].y)
00447     {
00448       if(nextIsPoint1)
00449       {
00450         point1 = point;
00451         nextIsPoint1 = false;
00452       }
00453       else
00454       point2 = point;
00455     }
00456   }
00457 
00458   if(Geometry::getIntersectionOfLines(side[2], lineToClip, point))
00459   {
00460     if(corner[2].x > point.x && point.x > corner[3].x)
00461     {
00462       if(nextIsPoint1)
00463       {
00464         point1 = point;
00465         nextIsPoint1 = false;
00466       }
00467       else
00468       point2 = point;
00469     }
00470   }
00471 
00472   if(Geometry::getIntersectionOfLines(side[3], lineToClip, point))
00473   {
00474     if(corner[3].y > point.y && point.y > corner[0].y)
00475     {
00476       if(nextIsPoint1)
00477       {
00478         point1 = point;
00479         nextIsPoint1 = false;
00480       }
00481       else
00482       point2 = point;
00483     }
00484   }
00485 
00486   if(nextIsPoint1)
00487     return false;
00488 
00489   if(getDistanceToLine(verticalLine, point1) < getDistanceToLine(verticalLine, point2) )
00490   {
00491     clipPoint1 = point1;
00492     clipPoint2 = point2;
00493   }
00494   else
00495   {
00496     clipPoint1 = point2;
00497     clipPoint2 = point1;
00498   }
00499   return true;
00500 }
00501 
00502 bool Geometry::isPointInsideRectangle
00503 (
00504  const Vector2<double>& bottomLeftCorner, 
00505  const Vector2<double>& topRightCorner,
00506  const Vector2<double>& point
00507 )
00508 {
00509   return(
00510     bottomLeftCorner.x <= point.x && point.x <= topRightCorner.x &&
00511     bottomLeftCorner.y <= point.y && point.y <= topRightCorner.y
00512     );
00513 }
00514 
00515 bool Geometry::isPointInsideRectangle
00516 (
00517  const Vector2<int>& bottomLeftCorner, 
00518  const Vector2<int>& topRightCorner,
00519  const Vector2<int>& point
00520 )
00521 {
00522   return(
00523     bottomLeftCorner.x <= point.x && point.x <= topRightCorner.x &&
00524     bottomLeftCorner.y <= point.y && point.y <= topRightCorner.y
00525     );
00526 }
00527 
00528 bool Geometry::clipPointInsideRectange(
00529   const Vector2<int>& bottomLeftCorner, 
00530   const Vector2<int>& topRightCorner,
00531   Vector2<int>& point
00532 )
00533 {
00534   bool clipped = false;
00535   if (point.x < bottomLeftCorner.x)
00536   {
00537     point.x = bottomLeftCorner.x;
00538     clipped = true;
00539   }
00540   if (point.x > topRightCorner.x)
00541   {
00542     point.x = topRightCorner.x;
00543     clipped = true;
00544   }
00545   if (point.y < bottomLeftCorner.y)
00546   {
00547     point.y = bottomLeftCorner.y;
00548     clipped = true;
00549   }
00550   if (point.y > topRightCorner.y)
00551   {
00552     point.y = topRightCorner.y;
00553     clipped = true;
00554   }
00555   return clipped;
00556 }
00557 
00558 bool Geometry::calculatePointOnField
00559 (
00560  const int x,
00561  const int y,
00562  const CameraMatrix& cameraMatrix,
00563  const CameraInfo& cameraInfo,
00564  Vector2<int>& pointOnField
00565  )
00566 {
00567 #ifndef _WIN32 // don't recalculate on real robot
00568   static 
00569 #endif
00570   double xFactor = cameraInfo.focalLengthInv,
00571          yFactor = cameraInfo.focalLengthInv;
00572 
00573   Vector3<double> 
00574     vectorToCenter(1, (cameraInfo.opticalCenter.x - x) * xFactor, (cameraInfo.opticalCenter.y - y) * yFactor);
00575   
00576   Vector3<double> 
00577     vectorToCenterWorld = cameraMatrix.rotation * vectorToCenter;
00578 
00579   //Is the point above the horizon ? - return
00580   if(vectorToCenterWorld.z > -5 * yFactor) return false;
00581   
00582   double a1 = cameraMatrix.translation.x,
00583          a2 = cameraMatrix.translation.y,
00584          a3 = cameraMatrix.translation.z,
00585          b1 = vectorToCenterWorld.x,
00586          b2 = vectorToCenterWorld.y,
00587          b3 = vectorToCenterWorld.z;
00588   
00589   pointOnField.x = int((a1 * b3 - a3 * b1) / b3 + 0.5);
00590   pointOnField.y = int((a2 * b3 - a3 * b2) / b3 + 0.5);
00591 
00592   return abs(pointOnField.x) < 10000 && abs(pointOnField.y) < 10000;
00593 }
00594 
00595 bool Geometry::calculatePointOnField
00596 (
00597  const int x,
00598  const int y,
00599  const CameraMatrix& cameraMatrix,
00600  const CameraMatrix& prevCameraMatrix,
00601  const CameraInfo& cameraInfo,
00602  Vector2<int>& pointOnField
00603  )
00604 {
00605   if(cameraInfo.simulated)
00606     return calculatePointOnField(x, y, cameraMatrix, cameraInfo, pointOnField);
00607   else
00608   {
00609     Vector2<int> pointOnField2;
00610     if(calculatePointOnField(x, y, cameraMatrix, cameraInfo, pointOnField) &&
00611        calculatePointOnField(x, y, prevCameraMatrix, cameraInfo, pointOnField2))
00612     {
00613       double scaleFactor = calculateScaleFactor(y, cameraMatrix.frameNumber, prevCameraMatrix.frameNumber, cameraInfo);
00614       // shift current percept towards old percept based on image row
00615       pointOnField.x += int((pointOnField2.x - pointOnField.x) * scaleFactor);
00616       pointOnField.y += int((pointOnField2.y - pointOnField.y) * scaleFactor);
00617       return true;
00618     }
00619     else
00620       return false;
00621   }
00622 }
00623 
00624 void Geometry::calculatePointInImage
00625 ( 
00626  const Vector2<int>& point,
00627  const CameraMatrix& cameraMatrix,
00628  const CameraInfo& cameraInfo,
00629  Vector2<int>& pointInImage
00630  )
00631 {
00632   Vector2<double> offset(point.x - cameraMatrix.translation.x,
00633                          point.y - cameraMatrix.translation.y);
00634   calculatePointByAngles(
00635     Vector2<double>(atan2(offset.y,offset.x),
00636                     -atan2(cameraMatrix.translation.z,offset.abs())),
00637     cameraMatrix, cameraInfo, 
00638     pointInImage
00639   );
00640 }
00641 
00642 /*
00643 not tested
00644 bool Geometry::ExpandOrClipLineWithRectangleCohenSutherland
00645 (
00646  const Vector2<int>& bottomLeft, 
00647  const Vector2<int>& topRight,
00648  Vector2<int>& point1, 
00649  Vector2<int>& point2
00650  )
00651 {
00652   while(!isPointInsideRectangle(bottomLeft, topRight, point1) )
00653   {
00654     point1 -= (point2 - point1);
00655   }
00656   while(!isPointInsideRectangle(bottomLeft, topRight, point2) )
00657   {
00658     point2 -= (point1 - point2);
00659   }
00660   return(clipLineWithRectangleCohenSutherland(bottomLeft, topRight, point1, point2));
00661 }
00662 */
00663 
00664 bool Geometry::getIntersectionPointsOfLineAndRectangle(
00665  const Vector2<int>& bottomLeft, 
00666  const Vector2<int>& topRight,
00667  const Geometry::Line line,
00668  Vector2<int>& point1, 
00669  Vector2<int>& point2
00670 )
00671 {
00672   int foundPoints=0;
00673   Vector2<double> point[2];
00674   if (line.direction.x!=0)
00675   {
00676     double y1=line.base.y+(bottomLeft.x-line.base.x)*line.direction.y/line.direction.x;
00677     if ((y1>=bottomLeft.y)&&(y1<=topRight.y))
00678     {
00679       point[foundPoints].x=bottomLeft.x;
00680       point[foundPoints++].y=y1;
00681     }
00682     double y2=line.base.y+(topRight.x-line.base.x)*line.direction.y/line.direction.x;
00683     if ((y2>=bottomLeft.y)&&(y2<=topRight.y))
00684     {
00685       point[foundPoints].x=topRight.x;
00686       point[foundPoints++].y=y2;
00687     }
00688   }
00689   if (line.direction.y!=0)
00690   {
00691     double x1=line.base.x+(bottomLeft.y-line.base.y)*line.direction.x/line.direction.y;
00692     if ((x1>=bottomLeft.x)&&(x1<=topRight.x)&&(foundPoints<2))
00693     {
00694       point[foundPoints].x=x1;
00695       point[foundPoints].y=bottomLeft.y;
00696       if ((foundPoints==0)||((point[0]-point[1]).abs()>0.1))
00697       {
00698         foundPoints++;
00699       }
00700     }
00701     double x2=line.base.x+(topRight.y-line.base.y)*line.direction.x/line.direction.y;
00702     if ((x2>=bottomLeft.x)&&(x2<=topRight.x)&&(foundPoints<2))
00703     {
00704       point[foundPoints].x=x2;
00705       point[foundPoints].y=topRight.y;
00706       if ((foundPoints==0)||((point[0]-point[1]).abs()>0.1))
00707       {
00708         foundPoints++;
00709       }
00710     }
00711   }
00712   switch (foundPoints)
00713   {
00714   case 1:
00715     point1.x=(int)point[0].x;
00716     point2.x=point1.x;
00717     point1.y=(int)point[0].y;
00718     point2.y=point1.y;
00719     foundPoints++;
00720     return true;
00721   case 2:
00722     if ((point[1]-point[0])*line.direction >0)
00723     {
00724       point1.x=(int)point[0].x;
00725       point1.y=(int)point[0].y;
00726       point2.x=(int)point[1].x;
00727       point2.y=(int)point[1].y;
00728     }
00729     else
00730     {
00731       point1.x=(int)point[1].x;
00732       point1.y=(int)point[1].y;
00733       point2.x=(int)point[0].x;
00734       point2.y=(int)point[0].y;
00735     }
00736     return true;
00737   default:
00738     return false;
00739   }
00740 }
00741 
00742 bool Geometry::clipLineWithRectangleCohenSutherland
00743 (
00744  const Vector2<int>& bottomLeft, 
00745  const Vector2<int>& topRight,
00746  Vector2<int>& point1, 
00747  Vector2<int>& point2
00748  )
00749 {
00750 //  bool point2WasRight = point2.x > point1.x;
00751 //  bool point2WasTop = point2.y > point1.y;
00752 
00753   int swap = 0;
00754 
00755   Vector2<int> p;
00756   int c1 = cohenSutherlandOutCode(bottomLeft, topRight, point1);
00757   int c2 = cohenSutherlandOutCode(bottomLeft, topRight, point2);
00758   
00759   if(c1 == 0 && c2 == 0) return false;
00760 
00761   while ( ( !(c1 == 0) || !(c2 == 0) ) && ( (c1&c2) == 0 ) ) 
00762   {
00763     if ( c1 == 0 ) 
00764     {
00765       p = point1;
00766       point1 = point2;
00767       point2 = p;
00768       c1 = c2; 
00769       swap++;
00770     }
00771     if (c1 & 1) 
00772     {
00773       point1.y = intersection(point1.x,point1.y,point2.x,point2.y,bottomLeft.x) ;
00774       point1.x = bottomLeft.x ; 
00775     }
00776     else if (c1&2)
00777     {
00778       point1.y = intersection(point1.x,point1.y,point2.x,point2.y,topRight.x) ;
00779       point1.x = topRight.x ; 
00780     }
00781     else if (c1&4)
00782     {
00783       point1.x = intersection(point1.y,point1.x,point2.y,point2.x,bottomLeft.y) ;
00784       point1.y = bottomLeft.y ; 
00785     }
00786     else if (c1&8)
00787     {
00788       point1.x = intersection(point1.y,point1.x,point2.y,point2.x,topRight.y) ;
00789       point1.y = topRight.y ; 
00790     }
00791     c1 = cohenSutherlandOutCode(bottomLeft, topRight, point1);
00792     c2 = cohenSutherlandOutCode(bottomLeft, topRight, point2);
00793   }
00794   if ( c1 == 0 && c2 == 0 )
00795   {
00796 /*    if(
00797       (point2WasTop && point2.y <= point1.y) ||
00798       (!point2WasTop && point2.y > point1.y) ||
00799       (point2WasRight && point2.x <= point1.x) ||
00800       (!point2WasRight && point2.x > point1.x) 
00801       )
00802 */
00803     if(swap % 2 == 1)
00804     {
00805       p = point1 ;
00806       point1 = point2;
00807       point2 = p ;
00808     }
00809     return true;
00810   }
00811   else
00812     return false;
00813 }
00814 
00815 int Geometry::intersection(int a1, int b1, int a2, int b2, int value)
00816 {
00817   int result = 0 ;
00818   if ( a2 - a1 != 0 )
00819     result = (int) (b1 +(double) (value-a1) / (a2-a1) * (b2-b1));
00820   else
00821     result = 32767;
00822   return(result);
00823 }
00824 
00825 Vector2<double> Geometry::relative2FieldCoord(RobotPose rp, double x, double y)
00826 {
00827   Vector3<double> relativePos(x, y, 0.0);
00828   Vector2<double> fieldPos(0.0, 0.0);
00829   RotationMatrix R;          
00830 
00831   R.fromKardanRPY(0,0, -rp.rotation);
00832   relativePos = R * relativePos;
00833 
00834   fieldPos.x = relativePos.x + rp.translation.x;
00835   fieldPos.y = relativePos.y + rp.translation.y;
00836   
00837   return fieldPos;
00838 }
00839 
00840 Vector2<double> Geometry::fieldCoord2Relative(RobotPose robotPose, Vector2<double> fieldCoord)
00841 {
00842   Vector2<double> relativeCoord;
00843   double distance = Geometry::distanceTo(robotPose.getPose(), fieldCoord);
00844   relativeCoord.x = distance * cos(Geometry::angleTo(robotPose.getPose(), fieldCoord));
00845   relativeCoord.y = distance * sin(Geometry::angleTo(robotPose.getPose(), fieldCoord));
00846   return relativeCoord;
00847 }
00848 
00849 
00850 bool Geometry::calculateBallInImage(const Vector2<double>& ballOffset,
00851                                     const CameraMatrix& cameraMatrix, const CameraInfo& cameraInfo, Circle& circle)
00852 {
00853   Vector2<double> offset(ballOffset.x - cameraMatrix.translation.x,
00854                          ballOffset.y - cameraMatrix.translation.y);
00855   double distance = offset.abs(),
00856          height = cameraMatrix.translation.z - ballRadius,
00857          cameraDistance = sqrt(sqr(distance) + sqr(height));
00858   circle.center = Vector2<double>(atan2(offset.y,offset.x),-atan2(height,distance));
00859   if(cameraDistance >= ballRadius)
00860   {
00861     double alpha = pi_2 - circle.center.y - acos(ballRadius / cameraDistance),
00862            yBottom = -atan2(height + cos(alpha) * ballRadius,
00863                             distance - sin(alpha) * ballRadius),
00864            beta = pi_2 - circle.center.y + acos(ballRadius / cameraDistance),
00865            yTop = -atan2(height + cos(beta) * ballRadius,
00866                          distance - sin(beta) * ballRadius);
00867     Vector2<int> top,
00868                  bottom;
00869     calculatePointByAngles(Vector2<double>(circle.center.x,yTop),cameraMatrix, cameraInfo, top);
00870     calculatePointByAngles(Vector2<double>(circle.center.x,yBottom),cameraMatrix, cameraInfo, bottom);
00871     circle.center.x = (top.x + bottom.x) / 2.0;
00872     circle.center.y = (top.y + bottom.y) / 2.0;
00873     circle.radius = (top - bottom).abs() / 2.0;
00874     return true;
00875   }
00876   else
00877     return false;
00878 }
00879 
00880 double Geometry::angleSizeToPixelSize(double angleSize, const CameraInfo& cameraInfo)
00881 {
00882   return cameraInfo.focalLength * tan(angleSize);
00883 }
00884 
00885 double Geometry::pixelSizeToAngleSize(double pixelSize, const CameraInfo& cameraInfo)
00886 {
00887   return atan(pixelSize * cameraInfo.focalLengthInv);  
00888 }
00889 
00890 double Geometry::getDistanceBySize
00891 (
00892  const CameraInfo& cameraInfo,
00893  double sizeInReality,
00894  double sizeInPixels
00895  )
00896 {
00897   double xFactor = cameraInfo.focalLength;
00898   return sizeInReality * xFactor / (sizeInPixels + 0.0001);
00899 }
00900 
00901 double Geometry::getDistanceBySize
00902 (
00903  const CameraInfo& cameraInfo,
00904  double sizeInReality,
00905  double sizeInPixels,
00906  int centerX,
00907  int centerY
00908  )
00909 {
00910   double mx = centerX;
00911   double my = centerY;
00912   double cx = cameraInfo.opticalCenter.x;
00913   double cy = cameraInfo.opticalCenter.y;
00914   double focalLenPow2 = cameraInfo.focalLenPow2;
00915   double sqrImgRadius = (mx-cx)*(mx-cx) + (my-cy)*(my-cy);
00916   double imgDistance = sqrt(focalLenPow2 + sqrImgRadius);
00917   return imgDistance*sizeInReality/(sizeInPixels + 0.0001);
00918 }
00919 
00920 double Geometry::getDistanceByAngleSize
00921 (
00922  double sizeInReality,
00923  double sizeAsAngle
00924  )
00925 {
00926   return (sizeInReality / 2.0) / tan(sizeAsAngle / 2.0 + 0.0001);
00927 }
00928 
00929 double Geometry::getBallDistanceByAngleSize
00930 (
00931  double sizeInReality,
00932  double sizeAsAngle
00933  )
00934 {
00935   return (sizeInReality / 2.0) / sin(sizeAsAngle / 2.0 + 0.0001);
00936 }
00937 
00938 double Geometry::getSizeByDistance
00939 (
00940  const CameraInfo& cameraInfo,
00941  double sizeInReality,
00942  double distance
00943 )
00944 {
00945   double xFactor = cameraInfo.focalLength;
00946   return sizeInReality / distance * xFactor;
00947 }
00948 
00949 
00950 double Geometry::getSizeByDistance
00951 (
00952  double sizeInReality,
00953  double distance,
00954  double imageWidthPixels,
00955  double imageWidthAngle
00956 )
00957 {
00958   double xFactor = imageWidthPixels / tan(imageWidthAngle / 2.0) / 2.0;
00959 //  return int(sizeInReality / double(distance - distancePanCenterToCamera) * xFactor);
00960   return sizeInReality / distance * xFactor;
00961 }
00962 
00963 Geometry::Line Geometry::calculateHorizon
00964 (
00965 const CameraMatrix& cameraMatrix,
00966 const CameraInfo& cameraInfo
00967 )
00968 {
00969   Line horizon;
00970   double r31 = cameraMatrix.rotation.c[0].z;
00971   double r32 = cameraMatrix.rotation.c[1].z;
00972   double r33 = cameraMatrix.rotation.c[2].z;
00973   
00974   if(r33 == 0) 
00975     r33 = 0.00001;
00976   
00977   double x1 = 0,
00978          x2 = cameraInfo.resolutionWidth - 1,
00979          v1 = cameraInfo.focalLength,
00980          v2 = cameraInfo.opticalCenter.x,
00981          v3 = cameraInfo.opticalCenter.y,
00982          y1 = (v3 * r33 + r31 * v1 + r32 * v2) / r33,
00983          y2 = (v3 * r33 + r31 * v1 - r32 * v2) / r33;
00984   
00985   // Mirror ends of horizon if Camera rotated to the left  
00986   if((cameraMatrix.rotation * Vector3<double>(0,0,1)).z < 0)
00987   {
00988     double t = x1;
00989     x1 = x2;
00990     x2 = t;
00991     t = y1;
00992     y1 = y2;
00993     y2 = t;
00994   }
00995 
00996   horizon.base.x = (x1 + x2) / 2.0;
00997   horizon.base.y = (y1 + y2) / 2.0;
00998   horizon.direction.x = x2 - x1;
00999   horizon.direction.y = y2 - y1;
01000   horizon.normalizeDirection();
01001   return horizon;
01002 }
01003 
01004 
01005 int Geometry::calculateLineSize
01006 (
01007  const Vector2<int>& pointInImage, 
01008  const CameraMatrix& cameraMatrix,
01009  const CameraInfo& cameraInfo
01010  )
01011 {
01012   Vector2<int> pointOnField; //position on field, relative to robot
01013   if(Geometry::calculatePointOnField(pointInImage.x, pointInImage.y, cameraMatrix, cameraInfo, pointOnField))
01014   {
01015     int distance = (int) sqrt(sqr(cameraMatrix.translation.z) + sqr(pointOnField.abs()));
01016     return (int)Geometry::getSizeByDistance(cameraInfo, 25, distance);
01017   }
01018   else
01019   {
01020     return 0;
01021   }
01022 }
01023 
01024 Geometry::CorrectedCoords Geometry::radialCorrectionLUT[cameraResolutionHeight_ERS7][cameraResolutionWidth_ERS7];
01025 
01026 void Geometry::setupRadialCorrection(const CameraInfo& cameraInfo)
01027 {
01028   double corrX, corrY;
01029   unsigned char cX, cY;
01030   for(int x=0; x<cameraInfo.resolutionWidth; x++)
01031     for(int y=0; y<cameraInfo.resolutionHeight; y++)
01032     {
01033       radialDistortionCorrection(cameraInfo, x, y, corrX, corrY);
01034       cX = (unsigned char) (corrX+0.5);
01035       cY = (unsigned char) (corrY+0.5);
01036       radialCorrectionLUT[y][x].x = cX;
01037       radialCorrectionLUT[y][x].y = cY;
01038     }
01039 }
01040 
01041 /*
01042 * Change log :
01043 * 
01044 * $Log: Geometry.cpp,v $
01045 * Revision 1.11  2004/06/16 13:39:14  thomas
01046 * update edge-specialist
01047 *
01048 * Revision 1.10  2004/06/14 23:20:08  spranger
01049 * -changed some functions in Geometry from int to double including ballradius(fieldimensions)
01050 * -maybe all Geometric-functions in Geometry should be as precise as possible, avoiding int to double conversion errors
01051 *
01052 * Revision 1.9  2004/06/13 21:22:14  nistico
01053 * Minor bug fixes
01054 *
01055 * Revision 1.8  2004/06/05 18:36:04  nistico
01056 * Cleanup
01057 *
01058 * Revision 1.7  2004/06/05 07:58:22  roefer
01059 * Compensation for motion distortions of images
01060 *
01061 * Revision 1.6  2004/06/04 21:47:13  juengel
01062 * Removed unused stuff.
01063 *
01064 * Revision 1.5  2004/06/04 21:35:10  juengel
01065 * Added getBallDistanceByAngleSize.
01066 *
01067 * Revision 1.4  2004/06/04 08:45:59  juengel
01068 * Added fieldCoord2Relative.
01069 *
01070 * Revision 1.3  2004/05/26 15:54:26  dueffert
01071 * camera matrix calculation cleaned up
01072 *
01073 * Revision 1.2  2004/05/22 22:52:03  juengel
01074 * Renamed ballP_osition to ballModel.
01075 *
01076 * Revision 1.1.1.1  2004/05/22 17:37:07  cvsadm
01077 * created new repository GT2004_WM
01078 *
01079 * Revision 1.20  2004/05/12 11:38:22  nistico
01080 * RadialDistortionCorrectionFast is now static
01081 *
01082 * Revision 1.19  2004/05/07 15:16:25  nistico
01083 * All geometry calculations are making use of intrinsic functions.
01084 * I updated most of the images processors to make correct use of this.
01085 * Please test if there are any problems, because i'm going to remove the
01086 * old code soon.
01087 *
01088 * Revision 1.18  2004/04/18 18:14:53  nistico
01089 * USE_INTRINSIC layout removed.
01090 * All functions properly replicated in intrinsic version.
01091 * However, image processor (MSH2004) making use of them get distorted visualization
01092 * of percepts, because drawing functions use the old parameters.
01093 * It has to be decided wheter to fully move to intrinsic, or discard it.
01094 *
01095 * Revision 1.17  2004/04/08 15:33:08  wachter
01096 * GT04 checkin of Microsoft-Hellounds
01097 *
01098 * Revision 1.17  2004/03/28 18:35:19  nistico
01099 * Temporarily created MSH2004ImageProcessor2, it has some important advancements compared to
01100 * the MSH2004ImageProcessor1 but it is untested on real robots yet, hence the creation of the
01101 * new module.
01102 * It will be removed soon, don't use it!
01103 *
01104 * Revision 1.16  2004/03/27 16:20:23  nistico
01105 * Little bug fixed (unrelated to ball measurement though)
01106 *
01107 * Revision 1.15  2004/03/25 15:13:00  nistico
01108 * Ball detection improved in MSH2004ImageProcessor
01109 * Ball distance measurement stabilized in MSH2004BallLocator (NOTE: to work with RIP, a small change has to be done in RIP code, just ask me...)
01110 * Fixed bugs with visualization of percepts (using intrinsic camera parameter based measurements)
01111 *
01112 * Revision 1.14  2004/03/23 12:41:36  nistico
01113 * MSH2004ImageProcessor improvements, distances now measured with intrinsic camera parameters
01114 *
01115 * Revision 1.16  2004/04/07 13:00:47  risler
01116 * ddd checkin after go04 - second part
01117 *
01118 * Revision 1.2  2004/03/29 10:15:21  risler
01119 * no message
01120 *
01121 * Revision 1.1.1.1  2004/03/29 08:28:42  Administrator
01122 * initial transfer from tamara
01123 *
01124 * Revision 1.14  2004/03/29 06:28:18  schmitt
01125 * Improved horizonCalculation
01126 *
01127 * Revision 1.15  2004/03/29 09:38:25  tim
01128 * did not compile with gcc
01129 *
01130 * Revision 1.14  2004/03/29 06:28:18  schmitt
01131 * Improved horizonCalculation
01132 *
01133 * Revision 1.13  2004/03/12 13:43:29  nistico
01134 * - Bugs fixed in USE_INTRINSIC mode
01135 *
01136 * Revision 1.12  2004/03/09 11:33:21  nistico
01137 * - Intrinsic parameters based measurements can now be triggered through a single conditional compilation
01138 * switch located in CameraInfo.h
01139 * - Implemented fast (look-up table based) radial distortion correction
01140 *
01141 * Revision 1.11  2004/02/10 10:48:05  nistico
01142 * Introduced Intrinsic camera parameters to perform geometric calculations (distance, angle, size...) without opening angle
01143 * Implemented radial distortion correction function
01144 * Implemented ball distance calculation based on size and intrinsic params (potentially more stable)
01145 * To Be Done: calculate intrinsic params for ERS7, as soon as we get our puppies back
01146 *
01147 * Revision 1.10  2004/01/28 18:40:43  mkunz
01148 * bug fixed in precalculated camera matrix
01149 *
01150 * Revision 1.9  2004/01/27 21:23:40  roefer
01151 * Camera matrix for ERS-7 is wrong. Reactivated simple version.
01152 *
01153 * Revision 1.8  2004/01/27 15:24:16  roefer
01154 * Sorry, checked in too much
01155 *
01156 * Revision 1.7  2004/01/23 00:13:24  roefer
01157 * ERS-7 simulation, first draft
01158 *
01159 * Revision 1.6  2004/01/08 18:20:54  mkunz
01160 * new precalculated cameramatrix for ERS7
01161 *
01162 * Revision 1.4  2004/01/01 10:58:52  roefer
01163 * RobotDimensions are in a class now
01164 *
01165 * Revision 1.3  2003/12/15 11:47:00  juengel
01166 * Introduced CameraInfo
01167 *
01168 * Revision 1.2  2003/11/15 17:12:13  juengel
01169 * Removed distancePanCenterToCamera from getDistanceBySize
01170 *
01171 * Revision 1.1  2003/10/07 10:13:24  cvsadm
01172 * Created GT2004 (M.J.)
01173 *
01174 * Revision 1.4  2003/09/26 16:06:40  mkunz
01175 * old comment for CameraMatrix calculation restored
01176 *
01177 * Revision 1.3  2003/08/18 11:50:21  juengel
01178 * Added calculateLineSize.
01179 *
01180 * Revision 1.2  2003/07/29 12:40:00  juengel
01181 * Added calculateHorizon
01182 *
01183 * Revision 1.1.1.1  2003/07/02 09:40:28  cvsadm
01184 * created new repository for the competitions in Padova from the 
01185 * tamara CVS (Tuesday 2:00 pm)
01186 *
01187 * removed unused solutions
01188 *
01189 * Revision 1.22  2003/06/23 12:10:40  dueffert
01190 * getIntersectionPoints...() completed
01191 *
01192 * Revision 1.21  2003/06/22 17:39:05  dueffert
01193 * getIntersectionPointsOfLineAndRectangle nearly complete
01194 *
01195 * Revision 1.20  2003/06/22 17:25:57  dueffert
01196 * getIntersectionPointsOfLineAndRectangle added
01197 *
01198 * Revision 1.19  2003/06/22 17:09:58  juengel
01199 * Added int version of function "distance".
01200 *
01201 * Revision 1.18  2003/06/17 13:43:56  dueffert
01202 * numbers replaced by constants
01203 *
01204 * Revision 1.17  2003/06/15 14:26:44  jhoffman
01205 * + moved "relative2FieldCoord" to Geometry
01206 * + added member function to ballp_osition to calculate the propagated position and speed for a given time
01207 * + propagated speed and time calculation using exponential decay instead of using an iterative calculation
01208 * + in motion you can now use propageted ball pos at 125 Hz rather then the framerate determined by cognition
01209 *
01210 * Revision 1.16  2003/06/12 16:54:09  juengel
01211 * Added getDistanceBySize and getSizeByDistance.
01212 *
01213 * Revision 1.15  2003/06/10 17:58:35  juengel
01214 * Fixed bug in Line Clipping.
01215 *
01216 * Revision 1.14  2003/04/16 07:00:17  roefer
01217 * Bremen GO checkin
01218 *
01219 * Revision 1.13  2003/04/15 15:52:07  risler
01220 * DDD GO 2003 code integrated
01221 *
01222 * Revision 1.12  2003/03/26 17:46:00  max
01223 * added getDistanceToEdge
01224 * optimized getDistanceToLine
01225 *
01226 * Revision 1.12  2003/04/01 16:51:09  roefer
01227 * CameraMatrix contains validity and is calculated in Geometry
01228 *
01229 * Revision 1.11  2003/03/18 13:48:18  roefer
01230 * Results of calculatePointOnField limited
01231 *
01232 * Revision 1.10  2003/01/19 11:38:08  juengel
01233 * int versions of clipLineWithQuadrangle and isPointInsideRectangle
01234 *
01235 * Revision 1.9  2003/01/15 08:19:48  juengel
01236 * Added "int" - version of getIntersectionOfLines.
01237 *
01238 * Revision 1.8  2002/12/14 19:45:54  roefer
01239 * paintLinesPerceptToImageView added
01240 *
01241 * Revision 1.7  2002/12/04 12:24:35  juengel
01242 * Changed parameter "pointOnField" of method calculatePointOnField() from Vector2<double> to Vector2<int>.
01243 *
01244 * Revision 1.6  2002/12/02 12:02:10  juengel
01245 * Finished cohen sutherland line clipping.
01246 *
01247 * Revision 1.5  2002/12/01 17:37:45  juengel
01248 * Worked at clipping functions.
01249 *
01250 * Revision 1.4  2002/11/28 18:53:53  juengel
01251 * RadarViewer3D shows images projected on ground.
01252 *
01253 * Revision 1.3  2002/11/19 15:43:04  dueffert
01254 * doxygen comments corrected
01255 *
01256 * Revision 1.2  2002/09/22 18:40:52  risler
01257 * added new math functions, removed GTMath library
01258 *
01259 * Revision 1.1  2002/09/22 09:15:34  risler
01260 * Geometry.h moved to directory Math
01261 *
01262 * Revision 1.1  2002/09/10 15:53:58  cvsadm
01263 * Created new project GT2003 (M.L.)
01264 * - Cleaned up the /Src/DataTypes directory
01265 * - Removed challenge related source code
01266 * - Removed processing of incoming audio data
01267 * - Renamed AcousticMessage to SoundRequest
01268 *
01269 * Revision 1.3  2002/06/13 18:22:10  dueffert
01270 * ray intersection added
01271 *
01272 * Revision 1.2  2002/05/29 16:06:05  dueffert
01273 * warning removed
01274 *
01275 * Revision 1.1.1.1  2002/05/10 12:40:33  cvsadm
01276 * Moved GT2002 Project from ute to tamara.
01277 *
01278 * Revision 1.12  2002/04/25 14:50:37  kallnik
01279 * changed double/float to double
01280 * added several #include GTMath
01281 *
01282 * PLEASE use double
01283 *
01284 * Revision 1.11  2002/04/16 15:44:04  dueffert
01285 * vectorTo(Pose, Vector) added
01286 *
01287 * Revision 1.2  2002/04/11 14:20:04  dueffert
01288 * dribble skill filled
01289 *
01290 * Revision 1.10  2002/04/08 19:53:14  juengel
01291 * Drawing of percept collections in images added.
01292 *
01293 * Revision 1.9  2002/04/06 02:30:55  loetzsch
01294 * added angleTo and distanceTo functions
01295 *
01296 * Revision 1.8  2002/04/04 18:43:31  juengel
01297 * Disatance and distance from point to line added.
01298 *
01299 * Revision 1.7  2002/04/02 10:30:34  juengel
01300 * GridImageProcessor enhanced.
01301 *
01302 * Revision 1.6  2002/03/29 14:55:48  juengel
01303 * "horizon aligned grid" started.
01304 *
01305 * Revision 1.5  2002/03/18 09:45:48  kallnik
01306 * GTMathTable updated
01307 * GTMathConfig updated
01308 * several doubles changed in GTMathValue
01309 *
01310 * Revision 1.4  2002/02/12 22:42:42  juengel
01311 * ImageProcessorTester improved.
01312 *
01313 * Revision 1.3  2002/02/11 00:56:36  loetzsch
01314 * added a constructor for class Circle
01315 *
01316 * Revision 1.2  2002/01/23 12:34:18  juengel
01317 * Kommentare eingefügt
01318 *
01319 * Revision 1.1  2002/01/22 14:54:47  juengel
01320 * Geometry eingeführt
01321 *
01322 *
01323 */

Generated on Thu Sep 23 19:57:38 2004 for GT2004 by doxygen 1.3.6