2011-09-20 13:57:40 +00:00
|
|
|
/**
|
|
|
|
* @file trigo.cpp
|
2013-01-26 17:49:48 +00:00
|
|
|
* @brief Trigonometric and geometric basic functions.
|
2011-09-20 13:57:40 +00:00
|
|
|
*/
|
2007-06-05 12:10:51 +00:00
|
|
|
|
2012-01-23 04:33:36 +00:00
|
|
|
#include <fctsys.h>
|
|
|
|
#include <macros.h>
|
|
|
|
#include <trigo.h>
|
// Dick Hollenbeck's KiROUND R&D
// This provides better project control over rounding to int from double
// than wxRound() did. This scheme provides better logging in Debug builds
// and it provides for compile time calculation of constants.
#include <stdio.h>
#include <assert.h>
#include <limits.h>
//-----<KiROUND KIT>------------------------------------------------------------
/**
* KiROUND
* rounds a floating point number to an int using
* "round halfway cases away from zero".
* In Debug build an assert fires if will not fit into an int.
*/
#if defined( DEBUG )
// DEBUG: a macro to capture line and file, then calls this inline
static inline int KiRound( double v, int line, const char* filename )
{
v = v < 0 ? v - 0.5 : v + 0.5;
if( v > INT_MAX + 0.5 )
{
printf( "%s: in file %s on line %d, val: %.16g too ' > 0 ' for int\n", __FUNCTION__, filename, line, v );
}
else if( v < INT_MIN - 0.5 )
{
printf( "%s: in file %s on line %d, val: %.16g too ' < 0 ' for int\n", __FUNCTION__, filename, line, v );
}
return int( v );
}
#define KiROUND( v ) KiRound( v, __LINE__, __FILE__ )
#else
// RELEASE: a macro so compile can pre-compute constants.
#define KiROUND( v ) int( (v) < 0 ? (v) - 0.5 : (v) + 0.5 )
#endif
//-----</KiROUND KIT>-----------------------------------------------------------
// Only a macro is compile time calculated, an inline function causes a static constructor
// in a situation like this.
// Therefore the Release build is best done with a MACRO not an inline function.
int Computed = KiROUND( 14.3 * 8 );
int main( int argc, char** argv )
{
for( double d = double(INT_MAX)-1; d < double(INT_MAX)+8; d += 2.0 )
{
int i = KiROUND( d );
printf( "t: %d %.16g\n", i, d );
}
return 0;
}
2012-04-19 06:55:45 +00:00
|
|
|
#include <common.h>
|
2013-01-26 17:49:48 +00:00
|
|
|
#include <math_for_graphics.h>
|
|
|
|
|
|
|
|
/* Function TestSegmentHit
|
|
|
|
* test for hit on line segment
|
|
|
|
* i.e. a reference point is within a given distance from segment
|
|
|
|
* aRefPoint = reference point to test
|
|
|
|
* aStart, aEnd are coordinates of end points segment
|
|
|
|
* aDist = maximum distance for hit
|
|
|
|
* Note: for calculation time reasons, the distance between the ref point
|
|
|
|
* and the segment is not always exactly calculated
|
|
|
|
* (we only know if the actual dist is < aDist, not exactly know this dist.
|
|
|
|
* Because many times we have horizontal or vertical segments,
|
|
|
|
* a special calcultaion is made for them
|
|
|
|
* Note: sometimes we need to calculate the distande between 2 points
|
|
|
|
* A square root should be calculated.
|
|
|
|
* However, because we just compare 2 distnaces, to avoid calculating square root,
|
|
|
|
* the square of distances are compared.
|
|
|
|
*/
|
|
|
|
static inline double square( int x ) // helper function to calculate x*x
|
2009-06-13 17:06:07 +00:00
|
|
|
{
|
2013-01-26 17:49:48 +00:00
|
|
|
return (double) x * x;
|
2009-06-13 17:06:07 +00:00
|
|
|
}
|
2013-05-01 17:32:36 +00:00
|
|
|
bool TestSegmentHit( const wxPoint &aRefPoint, wxPoint aStart,
|
|
|
|
wxPoint aEnd, int aDist )
|
2007-08-08 20:51:08 +00:00
|
|
|
{
|
2013-01-26 17:49:48 +00:00
|
|
|
// test for vertical or horizontal segment
|
|
|
|
if( aEnd.x == aStart.x )
|
2007-08-08 20:51:08 +00:00
|
|
|
{
|
2013-01-26 17:49:48 +00:00
|
|
|
// vertical segment
|
|
|
|
int ll = abs( aRefPoint.x - aStart.x );
|
2011-09-20 13:57:40 +00:00
|
|
|
|
2013-01-27 10:06:09 +00:00
|
|
|
if( ll > aDist )
|
2013-01-26 17:49:48 +00:00
|
|
|
return false;
|
2007-08-08 20:51:08 +00:00
|
|
|
|
2013-01-26 17:49:48 +00:00
|
|
|
// To have only one case to examine, ensure aEnd.y > aStart.y
|
|
|
|
if( aEnd.y < aStart.y )
|
|
|
|
EXCHG( aStart.y, aEnd.y );
|
2007-08-08 20:51:08 +00:00
|
|
|
|
2013-01-27 10:06:09 +00:00
|
|
|
if( aRefPoint.y <= aEnd.y && aRefPoint.y >= aStart.y )
|
2013-01-26 17:49:48 +00:00
|
|
|
return true;
|
|
|
|
|
|
|
|
// there is a special case: x,y near an end point (distance < dist )
|
|
|
|
// the distance should be carefully calculated
|
|
|
|
if( (aStart.y - aRefPoint.y) < aDist )
|
2007-08-08 20:51:08 +00:00
|
|
|
{
|
2013-01-26 17:49:48 +00:00
|
|
|
double dd = square( aRefPoint.x - aStart.x) +
|
|
|
|
square( aRefPoint.y - aStart.y );
|
2013-01-27 10:06:09 +00:00
|
|
|
if( dd <= square( aDist ) )
|
2013-01-26 17:49:48 +00:00
|
|
|
return true;
|
2007-08-08 20:51:08 +00:00
|
|
|
}
|
2013-01-26 17:49:48 +00:00
|
|
|
|
|
|
|
if( (aRefPoint.y - aEnd.y) < aDist )
|
2007-08-08 20:51:08 +00:00
|
|
|
{
|
2013-01-26 17:49:48 +00:00
|
|
|
double dd = square( aRefPoint.x - aEnd.x ) +
|
|
|
|
square( aRefPoint.y - aEnd.y );
|
2013-01-27 10:06:09 +00:00
|
|
|
if( dd <= square( aDist ) )
|
2007-08-08 20:51:08 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2013-01-26 17:49:48 +00:00
|
|
|
else if( aEnd.y == aStart.y )
|
2007-08-08 20:51:08 +00:00
|
|
|
{
|
2013-01-26 17:49:48 +00:00
|
|
|
// horizontal segment
|
|
|
|
int ll = abs( aRefPoint.y - aStart.y );
|
|
|
|
|
2013-01-27 10:06:09 +00:00
|
|
|
if( ll > aDist )
|
2013-01-26 17:49:48 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// To have only one case to examine, ensure xf > xi
|
|
|
|
if( aEnd.x < aStart.x )
|
|
|
|
EXCHG( aStart.x, aEnd.x );
|
|
|
|
|
2013-01-27 10:06:09 +00:00
|
|
|
if( aRefPoint.x <= aEnd.x && aRefPoint.x >= aStart.x )
|
2013-01-26 17:49:48 +00:00
|
|
|
return true;
|
|
|
|
|
|
|
|
// there is a special case: x,y near an end point (distance < dist )
|
|
|
|
// the distance should be carefully calculated
|
2013-01-27 10:06:09 +00:00
|
|
|
if( (aStart.x - aRefPoint.x) <= aDist )
|
2007-08-08 20:51:08 +00:00
|
|
|
{
|
2013-05-01 17:32:36 +00:00
|
|
|
double dd = square( aRefPoint.x - aStart.x ) +
|
2013-01-26 17:49:48 +00:00
|
|
|
square( aRefPoint.y - aStart.y );
|
2013-01-27 10:06:09 +00:00
|
|
|
if( dd <= square( aDist ) )
|
2007-08-08 20:51:08 +00:00
|
|
|
return true;
|
2013-01-26 17:49:48 +00:00
|
|
|
}
|
2007-08-08 20:51:08 +00:00
|
|
|
|
2013-01-27 10:06:09 +00:00
|
|
|
if( (aRefPoint.x - aEnd.x) <= aDist )
|
2013-01-26 17:49:48 +00:00
|
|
|
{
|
2013-05-01 17:32:36 +00:00
|
|
|
double dd = square( aRefPoint.x - aEnd.x ) +
|
|
|
|
square( aRefPoint.y - aEnd.y );
|
2013-01-27 10:06:09 +00:00
|
|
|
if( dd <= square( aDist ) )
|
2013-01-26 17:49:48 +00:00
|
|
|
return true;
|
2007-08-08 20:51:08 +00:00
|
|
|
}
|
|
|
|
}
|
2013-01-26 17:49:48 +00:00
|
|
|
else
|
2007-08-08 20:51:08 +00:00
|
|
|
{
|
2013-01-26 17:49:48 +00:00
|
|
|
// oblique segment:
|
|
|
|
// First, we need to calculate the distance between the point
|
|
|
|
// and the line defined by aStart and aEnd
|
|
|
|
// this dist should be < dist
|
|
|
|
//
|
|
|
|
// find a,slope such that aStart and aEnd lie on y = a + slope*x
|
|
|
|
double slope = (double) (aEnd.y - aStart.y) / (aEnd.x - aStart.x);
|
|
|
|
double a = (double) aStart.y - slope * aStart.x;
|
|
|
|
// find c,orthoslope such that (x,y) lies on y = c + orthoslope*x,
|
|
|
|
// where orthoslope=(-1/slope)
|
|
|
|
// to calculate xp, yp = near point from aRefPoint
|
|
|
|
// which is on the line defined by aStart, aEnd
|
|
|
|
double orthoslope = -1.0 / slope;
|
|
|
|
double c = (double) aRefPoint.y - orthoslope * aRefPoint.x;
|
|
|
|
// find nearest point to (x,y) on line defined by aStart, aEnd
|
|
|
|
double xp = (a - c) / (orthoslope - slope);
|
|
|
|
double yp = a + slope * xp;
|
|
|
|
// find distance to line, in fact the square of dist,
|
|
|
|
// because we just know if it is > or < aDist
|
|
|
|
double dd = square( aRefPoint.x - xp ) + square( aRefPoint.y - yp );
|
|
|
|
double dist = square( aDist );
|
|
|
|
|
2013-01-27 10:06:09 +00:00
|
|
|
if( dd > dist ) // this reference point is not a good candiadte.
|
2013-01-26 17:49:48 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// dd is < dist, therefore we should make a fine test
|
|
|
|
if( fabs( slope ) > 0.7 )
|
2007-08-08 20:51:08 +00:00
|
|
|
{
|
2013-01-26 17:49:48 +00:00
|
|
|
// line segment more vertical than horizontal
|
2013-01-27 10:06:09 +00:00
|
|
|
if( (aEnd.y > aStart.y && yp <= aEnd.y && yp >= aStart.y) ||
|
|
|
|
(aEnd.y < aStart.y && yp >= aEnd.y && yp <= aStart.y) )
|
2007-08-08 20:51:08 +00:00
|
|
|
return true;
|
|
|
|
}
|
2013-01-26 17:49:48 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// line segment more horizontal than vertical
|
2013-01-27 10:06:09 +00:00
|
|
|
if( (aEnd.x > aStart.x && xp <= aEnd.x && xp >= aStart.x) ||
|
|
|
|
(aEnd.x < aStart.x && xp >= aEnd.x && xp <= aStart.x) )
|
2013-01-26 17:49:48 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Here, the test point is still a good candidate,
|
|
|
|
// however it is not "between" the end points of the segment.
|
|
|
|
// It is "outside" the segment, but it could be near a segment end point
|
|
|
|
// Therefore, we test the dist from the test point to each segment end point
|
|
|
|
dd = square( aRefPoint.x - aEnd.x ) + square( aRefPoint.y - aEnd.y );
|
2013-01-27 10:06:09 +00:00
|
|
|
if( dd <= dist )
|
2013-01-26 17:49:48 +00:00
|
|
|
return true;
|
|
|
|
dd = square( aRefPoint.x - aStart.x ) + square( aRefPoint.y - aStart.y );
|
2013-01-27 10:06:09 +00:00
|
|
|
if( dd <= dist )
|
2013-01-26 17:49:48 +00:00
|
|
|
return true;
|
2007-08-08 20:51:08 +00:00
|
|
|
}
|
2009-11-23 15:16:50 +00:00
|
|
|
|
2013-01-26 17:49:48 +00:00
|
|
|
return false; // no hit
|
2007-08-08 20:51:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-05-01 17:32:36 +00:00
|
|
|
double ArcTangente( int dy, int dx )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2013-05-01 17:32:36 +00:00
|
|
|
|
|
|
|
/* gcc is surprisingly smart in optimizing these conditions in
|
|
|
|
a tree! */
|
|
|
|
|
|
|
|
if( dx == 0 && dy == 0 )
|
|
|
|
return 0;
|
2007-08-04 20:05:54 +00:00
|
|
|
|
|
|
|
if( dy == 0 )
|
|
|
|
{
|
|
|
|
if( dx >= 0 )
|
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return -1800;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( dx == 0 )
|
|
|
|
{
|
|
|
|
if( dy >= 0 )
|
|
|
|
return 900;
|
|
|
|
else
|
|
|
|
return -900;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( dx == dy )
|
|
|
|
{
|
|
|
|
if( dx >= 0 )
|
|
|
|
return 450;
|
|
|
|
else
|
|
|
|
return -1800 + 450;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( dx == -dy )
|
|
|
|
{
|
|
|
|
if( dx >= 0 )
|
|
|
|
return -450;
|
|
|
|
else
|
|
|
|
return 1800 - 450;
|
|
|
|
}
|
|
|
|
|
2013-05-02 18:06:58 +00:00
|
|
|
// Of course dy and dx are treated as double
|
|
|
|
return RAD2DECIDEG( atan2( dy, dx ) );
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-12-14 04:29:25 +00:00
|
|
|
void RotatePoint( int* pX, int* pY, double angle )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2011-09-20 13:57:40 +00:00
|
|
|
int tmp;
|
2007-08-04 20:05:54 +00:00
|
|
|
|
2013-05-01 17:32:36 +00:00
|
|
|
NORMALIZE_ANGLE_POS( angle );
|
2007-08-04 20:05:54 +00:00
|
|
|
|
2011-09-20 13:57:40 +00:00
|
|
|
// Cheap and dirty optimizations for 0, 90, 180, and 270 degrees.
|
2007-08-04 20:05:54 +00:00
|
|
|
if( angle == 0 )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if( angle == 900 ) /* sin = 1, cos = 0 */
|
|
|
|
{
|
|
|
|
tmp = *pX;
|
|
|
|
*pX = *pY;
|
|
|
|
*pY = -tmp;
|
|
|
|
}
|
|
|
|
else if( angle == 1800 ) /* sin = 0, cos = -1 */
|
|
|
|
{
|
|
|
|
*pX = -*pX;
|
|
|
|
*pY = -*pY;
|
|
|
|
}
|
|
|
|
else if( angle == 2700 ) /* sin = -1, cos = 0 */
|
|
|
|
{
|
|
|
|
tmp = *pX;
|
|
|
|
*pX = -*pY;
|
|
|
|
*pY = tmp;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-05-02 18:06:58 +00:00
|
|
|
double fangle = DECIDEG2RAD( angle );
|
2011-11-10 08:21:11 +00:00
|
|
|
double sinus = sin( fangle );
|
|
|
|
double cosinus = cos( fangle );
|
|
|
|
double fpx = (*pY * sinus ) + (*pX * cosinus );
|
|
|
|
double fpy = (*pY * cosinus ) - (*pX * sinus );
|
// Dick Hollenbeck's KiROUND R&D
// This provides better project control over rounding to int from double
// than wxRound() did. This scheme provides better logging in Debug builds
// and it provides for compile time calculation of constants.
#include <stdio.h>
#include <assert.h>
#include <limits.h>
//-----<KiROUND KIT>------------------------------------------------------------
/**
* KiROUND
* rounds a floating point number to an int using
* "round halfway cases away from zero".
* In Debug build an assert fires if will not fit into an int.
*/
#if defined( DEBUG )
// DEBUG: a macro to capture line and file, then calls this inline
static inline int KiRound( double v, int line, const char* filename )
{
v = v < 0 ? v - 0.5 : v + 0.5;
if( v > INT_MAX + 0.5 )
{
printf( "%s: in file %s on line %d, val: %.16g too ' > 0 ' for int\n", __FUNCTION__, filename, line, v );
}
else if( v < INT_MIN - 0.5 )
{
printf( "%s: in file %s on line %d, val: %.16g too ' < 0 ' for int\n", __FUNCTION__, filename, line, v );
}
return int( v );
}
#define KiROUND( v ) KiRound( v, __LINE__, __FILE__ )
#else
// RELEASE: a macro so compile can pre-compute constants.
#define KiROUND( v ) int( (v) < 0 ? (v) - 0.5 : (v) + 0.5 )
#endif
//-----</KiROUND KIT>-----------------------------------------------------------
// Only a macro is compile time calculated, an inline function causes a static constructor
// in a situation like this.
// Therefore the Release build is best done with a MACRO not an inline function.
int Computed = KiROUND( 14.3 * 8 );
int main( int argc, char** argv )
{
for( double d = double(INT_MAX)-1; d < double(INT_MAX)+8; d += 2.0 )
{
int i = KiROUND( d );
printf( "t: %d %.16g\n", i, d );
}
return 0;
}
2012-04-19 06:55:45 +00:00
|
|
|
*pX = KiROUND( fpx );
|
|
|
|
*pY = KiROUND( fpy );
|
2007-08-04 20:05:54 +00:00
|
|
|
}
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-12-14 04:29:25 +00:00
|
|
|
void RotatePoint( int* pX, int* pY, int cx, int cy, double angle )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2007-08-04 20:05:54 +00:00
|
|
|
int ox, oy;
|
2007-06-05 12:10:51 +00:00
|
|
|
|
2008-10-29 15:26:53 +00:00
|
|
|
ox = *pX - cx;
|
2007-08-04 20:05:54 +00:00
|
|
|
oy = *pY - cy;
|
2008-10-29 15:26:53 +00:00
|
|
|
|
2007-08-04 20:05:54 +00:00
|
|
|
RotatePoint( &ox, &oy, angle );
|
|
|
|
|
|
|
|
*pX = ox + cx;
|
|
|
|
*pY = oy + cy;
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
2007-08-04 20:05:54 +00:00
|
|
|
|
2011-12-14 04:29:25 +00:00
|
|
|
void RotatePoint( wxPoint* point, const wxPoint& centre, double angle )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2007-08-04 20:05:54 +00:00
|
|
|
int ox, oy;
|
|
|
|
|
2008-10-29 15:26:53 +00:00
|
|
|
ox = point->x - centre.x;
|
2007-08-04 20:05:54 +00:00
|
|
|
oy = point->y - centre.y;
|
2008-10-29 15:26:53 +00:00
|
|
|
|
2007-08-04 20:05:54 +00:00
|
|
|
RotatePoint( &ox, &oy, angle );
|
|
|
|
point->x = ox + centre.x;
|
|
|
|
point->y = oy + centre.y;
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-12-14 04:29:25 +00:00
|
|
|
void RotatePoint( double* pX, double* pY, double cx, double cy, double angle )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2007-08-04 20:05:54 +00:00
|
|
|
double ox, oy;
|
|
|
|
|
2008-10-29 15:26:53 +00:00
|
|
|
ox = *pX - cx;
|
2007-08-04 20:05:54 +00:00
|
|
|
oy = *pY - cy;
|
2008-10-29 15:26:53 +00:00
|
|
|
|
2007-08-04 20:05:54 +00:00
|
|
|
RotatePoint( &ox, &oy, angle );
|
2008-10-29 15:26:53 +00:00
|
|
|
|
2007-08-04 20:05:54 +00:00
|
|
|
*pX = ox + cx;
|
|
|
|
*pY = oy + cy;
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-12-14 04:29:25 +00:00
|
|
|
void RotatePoint( double* pX, double* pY, double angle )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2007-08-04 20:05:54 +00:00
|
|
|
double tmp;
|
|
|
|
|
2013-05-01 17:32:36 +00:00
|
|
|
NORMALIZE_ANGLE_POS( angle );
|
2007-08-04 20:05:54 +00:00
|
|
|
|
2011-09-20 13:57:40 +00:00
|
|
|
// Cheap and dirty optimizations for 0, 90, 180, and 270 degrees.
|
2007-08-04 20:05:54 +00:00
|
|
|
if( angle == 0 )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if( angle == 900 ) /* sin = 1, cos = 0 */
|
|
|
|
{
|
|
|
|
tmp = *pX;
|
|
|
|
*pX = *pY;
|
|
|
|
*pY = -tmp;
|
|
|
|
}
|
|
|
|
else if( angle == 1800 ) /* sin = 0, cos = -1 */
|
|
|
|
{
|
|
|
|
*pX = -*pX;
|
|
|
|
*pY = -*pY;
|
|
|
|
}
|
|
|
|
else if( angle == 2700 ) /* sin = -1, cos = 0 */
|
|
|
|
{
|
|
|
|
tmp = *pX;
|
|
|
|
*pX = -*pY;
|
|
|
|
*pY = tmp;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-05-02 18:06:58 +00:00
|
|
|
double fangle = DECIDEG2RAD( angle );
|
2011-11-10 08:21:11 +00:00
|
|
|
double sinus = sin( fangle );
|
|
|
|
double cosinus = cos( fangle );
|
2008-10-29 15:26:53 +00:00
|
|
|
|
2011-11-10 08:21:11 +00:00
|
|
|
double fpx = (*pY * sinus ) + (*pX * cosinus );
|
|
|
|
double fpy = (*pY * cosinus ) - (*pX * sinus );
|
2011-09-21 12:51:46 +00:00
|
|
|
*pX = fpx;
|
|
|
|
*pY = fpy;
|
2007-08-04 20:05:54 +00:00
|
|
|
}
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
2007-08-08 20:51:08 +00:00
|
|
|
|