2014-10-19 20:20:16 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2014 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
2019-06-02 09:51:47 +00:00
|
|
|
* Copyright (C) 2014 KiCad Developers, see AUTHORS.txt for contributors.
|
2014-10-19 20:20:16 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, you may find one here:
|
|
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
|
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
|
|
* or you may write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
|
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>
|
2019-09-07 22:16:40 +00:00
|
|
|
#include <geometry/seg.h>
|
2013-01-26 17:49:48 +00:00
|
|
|
|
2013-09-27 12:30:35 +00:00
|
|
|
// Returns true if the point P is on the segment S.
|
|
|
|
// faster than TestSegmentHit() because P should be exactly on S
|
|
|
|
// therefore works fine only for H, V and 45 deg segm (suitable for wires in eeschema)
|
|
|
|
bool IsPointOnSegment( const wxPoint& aSegStart, const wxPoint& aSegEnd,
|
|
|
|
const wxPoint& aTestPoint )
|
|
|
|
{
|
|
|
|
wxPoint vectSeg = aSegEnd - aSegStart; // Vector from S1 to S2
|
|
|
|
wxPoint vectPoint = aTestPoint - aSegStart; // Vector from S1 to P
|
|
|
|
|
|
|
|
// Use long long here to avoid overflow in calculations
|
|
|
|
if( (long long) vectSeg.x * vectPoint.y - (long long) vectSeg.y * vectPoint.x )
|
|
|
|
return false; /* Cross product non-zero, vectors not parallel */
|
|
|
|
|
|
|
|
if( ( (long long) vectSeg.x * vectPoint.x + (long long) vectSeg.y * vectPoint.y ) <
|
|
|
|
( (long long) vectPoint.x * vectPoint.x + (long long) vectPoint.y * vectPoint.y ) )
|
|
|
|
return false; /* Point not on segment */
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2013-09-21 18:09:41 +00:00
|
|
|
|
2014-10-19 20:20:16 +00:00
|
|
|
|
2013-09-27 12:30:35 +00:00
|
|
|
// Returns true if the segment 1 intersectd the segment 2.
|
2013-09-21 18:09:41 +00:00
|
|
|
bool SegmentIntersectsSegment( const wxPoint &a_p1_l1, const wxPoint &a_p2_l1,
|
2019-05-25 19:01:54 +00:00
|
|
|
const wxPoint &a_p1_l2, const wxPoint &a_p2_l2,
|
|
|
|
wxPoint* aIntersectionPoint )
|
2013-09-21 18:09:41 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
//We are forced to use 64bit ints because the internal units can oveflow 32bit ints when
|
|
|
|
// multiplied with each other, the alternative would be to scale the units down (i.e. divide
|
|
|
|
// by a fixed number).
|
|
|
|
long long dX_a, dY_a, dX_b, dY_b, dX_ab, dY_ab;
|
|
|
|
long long num_a, num_b, den;
|
|
|
|
|
|
|
|
//Test for intersection within the bounds of both line segments using line equations of the
|
|
|
|
// form:
|
|
|
|
// x_k(u_k) = u_k * dX_k + x_k(0)
|
|
|
|
// y_k(u_k) = u_k * dY_k + y_k(0)
|
|
|
|
// with 0 <= u_k <= 1 and k = [ a, b ]
|
|
|
|
|
|
|
|
dX_a = a_p2_l1.x - a_p1_l1.x;
|
|
|
|
dY_a = a_p2_l1.y - a_p1_l1.y;
|
|
|
|
dX_b = a_p2_l2.x - a_p1_l2.x;
|
|
|
|
dY_b = a_p2_l2.y - a_p1_l2.y;
|
|
|
|
dX_ab = a_p1_l2.x - a_p1_l1.x;
|
|
|
|
dY_ab = a_p1_l2.y - a_p1_l1.y;
|
|
|
|
|
|
|
|
den = dY_a * dX_b - dY_b * dX_a ;
|
|
|
|
|
|
|
|
//Check if lines are parallel
|
|
|
|
if( den == 0 )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
num_a = dY_ab * dX_b - dY_b * dX_ab;
|
|
|
|
num_b = dY_ab * dX_a - dY_a * dX_ab;
|
|
|
|
|
2019-05-25 19:01:54 +00:00
|
|
|
// Only compute the intersection point if requested
|
|
|
|
if( aIntersectionPoint )
|
|
|
|
{
|
|
|
|
*aIntersectionPoint = a_p1_l1;
|
|
|
|
aIntersectionPoint->x += KiROUND( dX_a * ( double )num_a / ( double )den );
|
|
|
|
aIntersectionPoint->y += KiROUND( dY_a * ( double )num_b / ( double )den );
|
|
|
|
}
|
2013-09-21 18:09:41 +00:00
|
|
|
|
|
|
|
if( den < 0 )
|
|
|
|
{
|
|
|
|
den = -den;
|
|
|
|
num_a = -num_a;
|
|
|
|
num_b = -num_b;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Test sign( u_a ) and return false if negative
|
|
|
|
if( num_a < 0 )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
//Test sign( u_b ) and return false if negative
|
|
|
|
if( num_b < 0 )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
//Test to ensure (u_a <= 1)
|
|
|
|
if( num_a > den )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
//Test to ensure (u_b <= 1)
|
|
|
|
if( num_b > den )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-10-12 21:08:14 +00:00
|
|
|
bool TestSegmentHit( const wxPoint &aRefPoint, wxPoint aStart, wxPoint aEnd, int aDist )
|
2009-06-13 17:06:07 +00:00
|
|
|
{
|
2017-10-12 21:08:14 +00:00
|
|
|
int xmin = aStart.x;
|
|
|
|
int xmax = aEnd.x;
|
|
|
|
int ymin = aStart.y;
|
|
|
|
int ymax = aEnd.y;
|
|
|
|
wxPoint delta = aStart - aRefPoint;
|
|
|
|
|
|
|
|
if( xmax < xmin )
|
|
|
|
std::swap( xmax, xmin );
|
|
|
|
|
|
|
|
if( ymax < ymin )
|
|
|
|
std::swap( ymax, ymin );
|
|
|
|
|
|
|
|
// First, check if we are outside of the bounding box
|
|
|
|
if( ( ymin - aRefPoint.y > aDist ) || ( aRefPoint.y - ymax > aDist ) )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if( ( xmin - aRefPoint.x > aDist ) || ( aRefPoint.x - xmax > aDist ) )
|
|
|
|
return false;
|
2009-11-23 15:16:50 +00:00
|
|
|
|
2017-10-12 21:08:14 +00:00
|
|
|
// Next, eliminate easy cases
|
|
|
|
if( aStart.x == aEnd.x && aRefPoint.y > ymin && aRefPoint.y < ymax )
|
|
|
|
return std::abs( delta.x ) <= aDist;
|
|
|
|
|
|
|
|
if( aStart.y == aEnd.y && aRefPoint.x > xmin && aRefPoint.x < xmax )
|
|
|
|
return std::abs( delta.y ) <= aDist;
|
|
|
|
|
2019-09-07 22:16:40 +00:00
|
|
|
SEG segment( aStart, aEnd );
|
2019-09-10 09:56:11 +00:00
|
|
|
return segment.PointCloserThan( aRefPoint, aDist + 1 );
|
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! */
|
2013-09-21 18:09:41 +00:00
|
|
|
|
2013-05-01 17:32:36 +00:00
|
|
|
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
|
2016-01-17 15:59:24 +00:00
|
|
|
return RAD2DECIDEG( atan2( (double) dy, (double) 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
|
|
|
}
|
|
|
|
|
2017-10-19 21:15:13 +00:00
|
|
|
void RotatePoint( VECTOR2I& point, const VECTOR2I& centre, double angle )
|
|
|
|
{
|
|
|
|
wxPoint c( centre.x, centre.y );
|
|
|
|
wxPoint p( point.x, point.y );
|
|
|
|
|
|
|
|
RotatePoint(&p, c, angle);
|
|
|
|
|
|
|
|
point.x = p.x;
|
|
|
|
point.y = p.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
|
|
|
}
|
2018-12-08 15:26:47 +00:00
|
|
|
|
|
|
|
|
|
|
|
const VECTOR2I GetArcCenter( const VECTOR2I& aStart, const VECTOR2I& aMid, const VECTOR2I& aEnd )
|
|
|
|
{
|
|
|
|
VECTOR2I center;
|
|
|
|
double yDelta_21 = aMid.y - aStart.y;
|
|
|
|
double xDelta_21 = aMid.x - aStart.x;
|
|
|
|
double yDelta_32 = aEnd.y - aMid.y;
|
|
|
|
double xDelta_32 = aEnd.x - aMid.x;
|
|
|
|
|
|
|
|
// This is a special case for aMid as the half-way point when aSlope = 0 and bSlope = inf
|
|
|
|
// or the other way around. In that case, the center lies in a straight line between
|
|
|
|
// aStart and aEnd
|
|
|
|
if( ( ( xDelta_21 == 0.0 ) && ( yDelta_32 == 0.0 ) ) ||
|
|
|
|
( ( yDelta_21 == 0.0 ) && ( xDelta_32 == 0.0 ) ) )
|
|
|
|
{
|
|
|
|
center.x = KiROUND( ( aStart.x + aEnd.x ) / 2.0 );
|
|
|
|
center.y = KiROUND( ( aStart.y + aEnd.y ) / 2.0 );
|
|
|
|
return center;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Prevent div=0 errors
|
|
|
|
if( xDelta_21 == 0.0 )
|
|
|
|
xDelta_21 = std::numeric_limits<double>::epsilon();
|
|
|
|
|
|
|
|
if( xDelta_32 == 0.0 )
|
|
|
|
xDelta_32 = -std::numeric_limits<double>::epsilon();
|
|
|
|
|
|
|
|
double aSlope = yDelta_21 / xDelta_21;
|
|
|
|
double bSlope = yDelta_32 / xDelta_32;
|
|
|
|
|
|
|
|
// If the points are colinear, the center is at infinity, so offset
|
|
|
|
// the slope by a minimal amount
|
|
|
|
// Warning: This will induce a small error in the center location
|
|
|
|
if( yDelta_32 * xDelta_21 == yDelta_21 * xDelta_32 )
|
|
|
|
{
|
|
|
|
aSlope += std::numeric_limits<double>::epsilon();
|
|
|
|
bSlope -= std::numeric_limits<double>::epsilon();
|
|
|
|
}
|
|
|
|
|
|
|
|
if( aSlope == 0.0 )
|
|
|
|
aSlope = std::numeric_limits<double>::epsilon();
|
|
|
|
|
|
|
|
if( bSlope == 0.0 )
|
|
|
|
bSlope = -std::numeric_limits<double>::epsilon();
|
|
|
|
|
|
|
|
|
|
|
|
double result = ( aSlope * bSlope * ( aStart.y - aEnd.y ) +
|
|
|
|
bSlope * ( aStart.x + aMid.x ) -
|
|
|
|
aSlope * ( aMid.x + aEnd.x ) ) / ( 2 * ( bSlope - aSlope ) );
|
|
|
|
|
|
|
|
center.x = KiROUND( Clamp<double>( double( std::numeric_limits<int>::min() / 2 ),
|
|
|
|
result,
|
|
|
|
double( std::numeric_limits<int>::max() / 2 ) ) );
|
|
|
|
|
|
|
|
result = ( ( ( aStart.x + aMid.x ) / 2.0 - center.x ) / aSlope +
|
|
|
|
( aStart.y + aMid.y ) / 2.0 );
|
|
|
|
|
|
|
|
center.y = KiROUND( Clamp<double>( double( std::numeric_limits<int>::min() / 2 ),
|
|
|
|
result,
|
|
|
|
double( std::numeric_limits<int>::max() / 2 ) ) );
|
|
|
|
|
|
|
|
return center;
|
|
|
|
}
|