You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

346 lines
9.3 KiB

// 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; }
14 years ago
14 years ago
// 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; }
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2014 Jean-Pierre Charras, jp.charras at wanadoo.fr
  5. * Copyright (C) 2014 KiCad Developers, see CHANGELOG.TXT for contributors.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, you may find one here:
  19. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  20. * or you may search the http://www.gnu.org website for the version 2 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. /**
  25. * @file trigo.cpp
  26. * @brief Trigonometric and geometric basic functions.
  27. */
  28. #include <fctsys.h>
  29. #include <macros.h>
  30. #include <trigo.h>
  31. #include <common.h>
  32. #include <math_for_graphics.h>
  33. // Returns true if the point P is on the segment S.
  34. // faster than TestSegmentHit() because P should be exactly on S
  35. // therefore works fine only for H, V and 45 deg segm (suitable for wires in eeschema)
  36. bool IsPointOnSegment( const wxPoint& aSegStart, const wxPoint& aSegEnd,
  37. const wxPoint& aTestPoint )
  38. {
  39. wxPoint vectSeg = aSegEnd - aSegStart; // Vector from S1 to S2
  40. wxPoint vectPoint = aTestPoint - aSegStart; // Vector from S1 to P
  41. // Use long long here to avoid overflow in calculations
  42. if( (long long) vectSeg.x * vectPoint.y - (long long) vectSeg.y * vectPoint.x )
  43. return false; /* Cross product non-zero, vectors not parallel */
  44. if( ( (long long) vectSeg.x * vectPoint.x + (long long) vectSeg.y * vectPoint.y ) <
  45. ( (long long) vectPoint.x * vectPoint.x + (long long) vectPoint.y * vectPoint.y ) )
  46. return false; /* Point not on segment */
  47. return true;
  48. }
  49. // Returns true if the segment 1 intersectd the segment 2.
  50. bool SegmentIntersectsSegment( const wxPoint &a_p1_l1, const wxPoint &a_p2_l1,
  51. const wxPoint &a_p1_l2, const wxPoint &a_p2_l2 )
  52. {
  53. //We are forced to use 64bit ints because the internal units can oveflow 32bit ints when
  54. // multiplied with each other, the alternative would be to scale the units down (i.e. divide
  55. // by a fixed number).
  56. long long dX_a, dY_a, dX_b, dY_b, dX_ab, dY_ab;
  57. long long num_a, num_b, den;
  58. //Test for intersection within the bounds of both line segments using line equations of the
  59. // form:
  60. // x_k(u_k) = u_k * dX_k + x_k(0)
  61. // y_k(u_k) = u_k * dY_k + y_k(0)
  62. // with 0 <= u_k <= 1 and k = [ a, b ]
  63. dX_a = a_p2_l1.x - a_p1_l1.x;
  64. dY_a = a_p2_l1.y - a_p1_l1.y;
  65. dX_b = a_p2_l2.x - a_p1_l2.x;
  66. dY_b = a_p2_l2.y - a_p1_l2.y;
  67. dX_ab = a_p1_l2.x - a_p1_l1.x;
  68. dY_ab = a_p1_l2.y - a_p1_l1.y;
  69. den = dY_a * dX_b - dY_b * dX_a ;
  70. //Check if lines are parallel
  71. if( den == 0 )
  72. return false;
  73. num_a = dY_ab * dX_b - dY_b * dX_ab;
  74. num_b = dY_ab * dX_a - dY_a * dX_ab;
  75. //We wont calculate directly the u_k of the intersection point to avoid floating point
  76. // division but they could be calculated with:
  77. // u_a = (float) num_a / (float) den;
  78. // u_b = (float) num_b / (float) den;
  79. if( den < 0 )
  80. {
  81. den = -den;
  82. num_a = -num_a;
  83. num_b = -num_b;
  84. }
  85. //Test sign( u_a ) and return false if negative
  86. if( num_a < 0 )
  87. return false;
  88. //Test sign( u_b ) and return false if negative
  89. if( num_b < 0 )
  90. return false;
  91. //Test to ensure (u_a <= 1)
  92. if( num_a > den )
  93. return false;
  94. //Test to ensure (u_b <= 1)
  95. if( num_b > den )
  96. return false;
  97. return true;
  98. }
  99. bool TestSegmentHit( const wxPoint &aRefPoint, wxPoint aStart, wxPoint aEnd, int aDist )
  100. {
  101. int xmin = aStart.x;
  102. int xmax = aEnd.x;
  103. int ymin = aStart.y;
  104. int ymax = aEnd.y;
  105. wxPoint delta = aStart - aRefPoint;
  106. if( xmax < xmin )
  107. std::swap( xmax, xmin );
  108. if( ymax < ymin )
  109. std::swap( ymax, ymin );
  110. // First, check if we are outside of the bounding box
  111. if( ( ymin - aRefPoint.y > aDist ) || ( aRefPoint.y - ymax > aDist ) )
  112. return false;
  113. if( ( xmin - aRefPoint.x > aDist ) || ( aRefPoint.x - xmax > aDist ) )
  114. return false;
  115. // Next, eliminate easy cases
  116. if( aStart.x == aEnd.x && aRefPoint.y > ymin && aRefPoint.y < ymax )
  117. return std::abs( delta.x ) <= aDist;
  118. if( aStart.y == aEnd.y && aRefPoint.x > xmin && aRefPoint.x < xmax )
  119. return std::abs( delta.y ) <= aDist;
  120. wxPoint len = aEnd - aStart;
  121. // Precision note here:
  122. // These are 32-bit integers, so squaring requires 64 bits to represent
  123. // exactly. 64-bit Doubles have only 52 bits in the mantissa, so we start to lose
  124. // precision at 2^53, which corresponds to ~ ±1nm @ 9.5cm, 2nm at 90cm, etc...
  125. // Long doubles avoid this ambiguity as well as the more expensive denormal double calc
  126. // Long doubles usually (sometimes more if SIMD) have at least 64 bits in the mantissa
  127. long double length_square = (long double) len.x * len.x + (long double) len.y * len.y;
  128. long double cross = std::abs( (long double) len.x * delta.y - (long double) len.y * delta.x );
  129. long double dist_square = (long double) aDist * aDist;
  130. // The perpendicular distance to a line is the vector magnitude of the line from
  131. // a test point to the test line. That is the 2d determinant. Because we handled
  132. // the zero length case above, so we are guaranteed a unique solution.
  133. return ( ( length_square >= cross && dist_square >= cross ) ||
  134. ( length_square * dist_square >= cross * cross ) );
  135. }
  136. double ArcTangente( int dy, int dx )
  137. {
  138. /* gcc is surprisingly smart in optimizing these conditions in
  139. a tree! */
  140. if( dx == 0 && dy == 0 )
  141. return 0;
  142. if( dy == 0 )
  143. {
  144. if( dx >= 0 )
  145. return 0;
  146. else
  147. return -1800;
  148. }
  149. if( dx == 0 )
  150. {
  151. if( dy >= 0 )
  152. return 900;
  153. else
  154. return -900;
  155. }
  156. if( dx == dy )
  157. {
  158. if( dx >= 0 )
  159. return 450;
  160. else
  161. return -1800 + 450;
  162. }
  163. if( dx == -dy )
  164. {
  165. if( dx >= 0 )
  166. return -450;
  167. else
  168. return 1800 - 450;
  169. }
  170. // Of course dy and dx are treated as double
  171. return RAD2DECIDEG( atan2( (double) dy, (double) dx ) );
  172. }
  173. void RotatePoint( int* pX, int* pY, double angle )
  174. {
  175. int tmp;
  176. NORMALIZE_ANGLE_POS( angle );
  177. // Cheap and dirty optimizations for 0, 90, 180, and 270 degrees.
  178. if( angle == 0 )
  179. return;
  180. if( angle == 900 ) /* sin = 1, cos = 0 */
  181. {
  182. tmp = *pX;
  183. *pX = *pY;
  184. *pY = -tmp;
  185. }
  186. else if( angle == 1800 ) /* sin = 0, cos = -1 */
  187. {
  188. *pX = -*pX;
  189. *pY = -*pY;
  190. }
  191. else if( angle == 2700 ) /* sin = -1, cos = 0 */
  192. {
  193. tmp = *pX;
  194. *pX = -*pY;
  195. *pY = tmp;
  196. }
  197. else
  198. {
  199. double fangle = DECIDEG2RAD( angle );
  200. double sinus = sin( fangle );
  201. double cosinus = cos( fangle );
  202. double fpx = (*pY * sinus ) + (*pX * cosinus );
  203. double fpy = (*pY * cosinus ) - (*pX * sinus );
  204. *pX = KiROUND( fpx );
  205. *pY = KiROUND( fpy );
  206. }
  207. }
  208. void RotatePoint( int* pX, int* pY, int cx, int cy, double angle )
  209. {
  210. int ox, oy;
  211. ox = *pX - cx;
  212. oy = *pY - cy;
  213. RotatePoint( &ox, &oy, angle );
  214. *pX = ox + cx;
  215. *pY = oy + cy;
  216. }
  217. void RotatePoint( wxPoint* point, const wxPoint& centre, double angle )
  218. {
  219. int ox, oy;
  220. ox = point->x - centre.x;
  221. oy = point->y - centre.y;
  222. RotatePoint( &ox, &oy, angle );
  223. point->x = ox + centre.x;
  224. point->y = oy + centre.y;
  225. }
  226. void RotatePoint( VECTOR2I& point, const VECTOR2I& centre, double angle )
  227. {
  228. wxPoint c( centre.x, centre.y );
  229. wxPoint p( point.x, point.y );
  230. RotatePoint(&p, c, angle);
  231. point.x = p.x;
  232. point.y = p.y;
  233. }
  234. void RotatePoint( double* pX, double* pY, double cx, double cy, double angle )
  235. {
  236. double ox, oy;
  237. ox = *pX - cx;
  238. oy = *pY - cy;
  239. RotatePoint( &ox, &oy, angle );
  240. *pX = ox + cx;
  241. *pY = oy + cy;
  242. }
  243. void RotatePoint( double* pX, double* pY, double angle )
  244. {
  245. double tmp;
  246. NORMALIZE_ANGLE_POS( angle );
  247. // Cheap and dirty optimizations for 0, 90, 180, and 270 degrees.
  248. if( angle == 0 )
  249. return;
  250. if( angle == 900 ) /* sin = 1, cos = 0 */
  251. {
  252. tmp = *pX;
  253. *pX = *pY;
  254. *pY = -tmp;
  255. }
  256. else if( angle == 1800 ) /* sin = 0, cos = -1 */
  257. {
  258. *pX = -*pX;
  259. *pY = -*pY;
  260. }
  261. else if( angle == 2700 ) /* sin = -1, cos = 0 */
  262. {
  263. tmp = *pX;
  264. *pX = -*pY;
  265. *pY = tmp;
  266. }
  267. else
  268. {
  269. double fangle = DECIDEG2RAD( angle );
  270. double sinus = sin( fangle );
  271. double cosinus = cos( fangle );
  272. double fpx = (*pY * sinus ) + (*pX * cosinus );
  273. double fpy = (*pY * cosinus ) - (*pX * sinus );
  274. *pX = fpx;
  275. *pY = fpy;
  276. }
  277. }