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.

471 lines
12 KiB

17 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
// 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
// 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
// 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
17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
  5. * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
  6. * Copyright (C) 2012 Wayne Stambaugh <stambaughw@verizon.net>
  7. * Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License
  11. * as published by the Free Software Foundation; either version 2
  12. * of the License, or (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, you may find one here:
  21. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  22. * or you may search the http://www.gnu.org website for the version 2 license,
  23. * or you may write to the Free Software Foundation, Inc.,
  24. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  25. */
  26. /**
  27. * @file base_screen.cpp
  28. * @brief BASE_SCREEN object implementation.
  29. */
  30. #include <fctsys.h>
  31. #include <macros.h>
  32. #include <common.h>
  33. #include <base_struct.h>
  34. #include <base_screen.h>
  35. #include <id.h>
  36. #include <base_units.h>
  37. wxString BASE_SCREEN::m_PageLayoutDescrFileName; // the name of the page layout descr file.
  38. BASE_SCREEN::BASE_SCREEN( KICAD_T aType ) :
  39. EDA_ITEM( aType )
  40. {
  41. m_UndoRedoCountMax = DEFAULT_MAX_UNDO_ITEMS;
  42. m_FirstRedraw = true;
  43. m_ScreenNumber = 1;
  44. m_NumberOfScreens = 1; // Hierarchy: Root: ScreenNumber = 1
  45. m_Zoom = 32.0;
  46. m_Grid.m_Size = wxRealPoint( 50, 50 ); // Default grid size
  47. m_Grid.m_CmdId = ID_POPUP_GRID_LEVEL_50;
  48. m_Center = true;
  49. m_IsPrinting = false;
  50. m_ScrollPixelsPerUnitX = 1;
  51. m_ScrollPixelsPerUnitY = 1;
  52. m_FlagModified = false; // Set when any change is made on board.
  53. m_FlagSave = false; // Used in auto save set when an auto save is required.
  54. SetCurItem( NULL );
  55. }
  56. BASE_SCREEN::~BASE_SCREEN()
  57. {
  58. }
  59. void BASE_SCREEN::InitDataPoints( const wxSize& aPageSizeIU )
  60. {
  61. if( m_Center )
  62. {
  63. m_crossHairPosition.x = 0;
  64. m_crossHairPosition.y = 0;
  65. m_DrawOrg.x = -aPageSizeIU.x / 2;
  66. m_DrawOrg.y = -aPageSizeIU.y / 2;
  67. }
  68. else
  69. {
  70. m_crossHairPosition.x = aPageSizeIU.x / 2;
  71. m_crossHairPosition.y = aPageSizeIU.y / 2;
  72. m_DrawOrg.x = 0;
  73. m_DrawOrg.y = 0;
  74. }
  75. m_O_Curseur.x = m_O_Curseur.y = 0;
  76. }
  77. double BASE_SCREEN::GetScalingFactor() const
  78. {
  79. double scale = 1.0 / GetZoom();
  80. return scale;
  81. }
  82. void BASE_SCREEN::SetScalingFactor( double aScale )
  83. {
  84. // Limit zoom to max and min allowed values:
  85. double zoom = Clamp( GetMinAllowedZoom(), aScale, GetMaxAllowedZoom() );
  86. SetZoom( zoom );
  87. }
  88. bool BASE_SCREEN::SetFirstZoom()
  89. {
  90. return SetZoom( GetMinAllowedZoom() );
  91. }
  92. bool BASE_SCREEN::SetLastZoom()
  93. {
  94. return SetZoom( GetMaxAllowedZoom() );
  95. }
  96. bool BASE_SCREEN::SetZoom( double iu_per_du )
  97. {
  98. if( iu_per_du == m_Zoom )
  99. return false;
  100. //wxLogDebug( "Zoom:%.16g 1/Zoom:%.16g", iu_per_du, 1/iu_per_du );
  101. if( iu_per_du < GetMinAllowedZoom() )
  102. return false;
  103. if( iu_per_du > GetMaxAllowedZoom() )
  104. return false;
  105. m_Zoom = iu_per_du;
  106. return true;
  107. }
  108. bool BASE_SCREEN::SetNextZoom()
  109. {
  110. for( unsigned i=0; i < m_ZoomList.size(); ++i )
  111. {
  112. if( m_Zoom < m_ZoomList[i] )
  113. {
  114. SetZoom( m_ZoomList[i] );
  115. return true;
  116. }
  117. }
  118. return false;
  119. }
  120. bool BASE_SCREEN::SetPreviousZoom()
  121. {
  122. for( unsigned i = m_ZoomList.size(); i != 0; --i )
  123. {
  124. if( m_Zoom > m_ZoomList[i - 1] )
  125. {
  126. SetZoom( m_ZoomList[i - 1] );
  127. return true;
  128. }
  129. }
  130. return false;
  131. }
  132. /* Build the list of human readable grid list.
  133. * The list shows the grid size both in mils or mm.
  134. * aMmFirst = true to have mm first and mils after
  135. * false to have mils first and mm after
  136. */
  137. int BASE_SCREEN::BuildGridsChoiceList( wxArrayString& aGridsList, bool aMmFirst) const
  138. {
  139. wxString msg;
  140. wxRealPoint curr_grid_size = GetGridSize();
  141. int idx = -1;
  142. int idx_usergrid = -1;
  143. for( size_t i = 0; i < GetGridCount(); i++ )
  144. {
  145. const GRID_TYPE& grid = m_grids[i];
  146. double gridValueMils = To_User_Unit( INCHES, grid.m_Size.x ) * 1000;
  147. double gridValue_mm = To_User_Unit( MILLIMETRES, grid.m_Size.x );
  148. if( grid.m_CmdId == ID_POPUP_GRID_USER )
  149. {
  150. msg = _( "Custom User Grid" );
  151. idx_usergrid = i;
  152. }
  153. else
  154. {
  155. if( aMmFirst )
  156. msg.Printf( _( "Grid: %.4f mm (%.2f mils)" ),
  157. gridValue_mm, gridValueMils );
  158. else
  159. msg.Printf( _( "Grid: %.2f mils (%.4f mm)" ),
  160. gridValueMils, gridValue_mm );
  161. }
  162. aGridsList.Add( msg );
  163. if( curr_grid_size == grid.m_Size )
  164. idx = i;
  165. }
  166. if( idx < 0 )
  167. idx = idx_usergrid;
  168. return idx;
  169. }
  170. void BASE_SCREEN::SetGridList( GRIDS& gridlist )
  171. {
  172. if( !m_grids.empty() )
  173. m_grids.clear();
  174. m_grids = gridlist;
  175. }
  176. int BASE_SCREEN::SetGrid( const wxRealPoint& size )
  177. {
  178. wxASSERT( !m_grids.empty() );
  179. GRID_TYPE nearest_grid = m_grids[0];
  180. int gridIdx = 0;
  181. for( unsigned i = 0; i < m_grids.size(); i++ )
  182. {
  183. if( m_grids[i].m_Size == size )
  184. {
  185. m_Grid = m_grids[i];
  186. return m_grids[i].m_CmdId - ID_POPUP_GRID_LEVEL_1000;
  187. }
  188. // keep track of the nearest larger grid size, if the exact size is not found
  189. if ( size.x < m_grids[i].m_Size.x )
  190. {
  191. gridIdx = m_grids[i].m_CmdId - ID_POPUP_GRID_LEVEL_1000;
  192. nearest_grid = m_grids[i];
  193. }
  194. }
  195. m_Grid = nearest_grid;
  196. wxLogWarning( _( "Grid size( %f, %f ) not in grid list, falling back "
  197. "to grid size( %f, %f )." ),
  198. size.x, size.y, m_Grid.m_Size.x, m_Grid.m_Size.y );
  199. return gridIdx;
  200. }
  201. int BASE_SCREEN::SetGrid( int aCommandId )
  202. {
  203. wxASSERT( !m_grids.empty() );
  204. for( unsigned i = 0; i < m_grids.size(); i++ )
  205. {
  206. if( m_grids[i].m_CmdId == aCommandId )
  207. {
  208. m_Grid = m_grids[i];
  209. return m_grids[i].m_CmdId - ID_POPUP_GRID_LEVEL_1000;
  210. }
  211. }
  212. m_Grid = m_grids[0];
  213. wxLogWarning( _( "Grid ID %d not in grid list, falling back to "
  214. "grid size( %g, %g )." ), aCommandId,
  215. m_Grid.m_Size.x, m_Grid.m_Size.y );
  216. return m_grids[0].m_CmdId - ID_POPUP_GRID_LEVEL_1000;
  217. }
  218. void BASE_SCREEN::AddGrid( const GRID_TYPE& grid )
  219. {
  220. for( unsigned i = 0; i < m_grids.size(); i++ )
  221. {
  222. if( m_grids[i].m_Size == grid.m_Size && grid.m_CmdId != ID_POPUP_GRID_USER )
  223. {
  224. wxLogDebug( wxT( "Discarding duplicate grid size( %g, %g )." ),
  225. grid.m_Size.x, grid.m_Size.y );
  226. return;
  227. }
  228. if( m_grids[i].m_CmdId == grid.m_CmdId )
  229. {
  230. wxLogDebug( wxT( "Changing grid ID %d from size( %g, %g ) to " ) \
  231. wxT( "size( %g, %g )." ),
  232. grid.m_CmdId, m_grids[i].m_Size.x,
  233. m_grids[i].m_Size.y, grid.m_Size.x, grid.m_Size.y );
  234. m_grids[i].m_Size = grid.m_Size;
  235. return;
  236. }
  237. }
  238. m_grids.push_back( grid );
  239. }
  240. void BASE_SCREEN::AddGrid( const wxRealPoint& size, int id )
  241. {
  242. GRID_TYPE grid;
  243. grid.m_Size = size;
  244. grid.m_CmdId = id;
  245. AddGrid( grid );
  246. }
  247. void BASE_SCREEN::AddGrid( const wxRealPoint& size, EDA_UNITS_T aUnit, int id )
  248. {
  249. wxRealPoint new_size;
  250. GRID_TYPE new_grid;
  251. new_size.x = From_User_Unit( aUnit, size.x );
  252. new_size.y = From_User_Unit( aUnit, size.y );
  253. new_grid.m_CmdId = id;
  254. new_grid.m_Size = new_size;
  255. AddGrid( new_grid );
  256. }
  257. GRID_TYPE& BASE_SCREEN::GetGrid( size_t aIndex )
  258. {
  259. wxCHECK_MSG( !m_grids.empty() && aIndex < m_grids.size(), m_Grid,
  260. wxT( "Cannot get grid object outside the bounds of the grid list." ) );
  261. return m_grids[ aIndex ];
  262. }
  263. bool BASE_SCREEN::GridExists( int aCommandId )
  264. {
  265. // tests for grid command ID (not an index in grid list, but a wxID) exists in grid list.
  266. for( unsigned i = 0; i < m_grids.size(); i++ )
  267. {
  268. if( m_grids[i].m_CmdId == aCommandId )
  269. return true;
  270. }
  271. return false;
  272. }
  273. wxPoint BASE_SCREEN::getNearestGridPosition( const wxPoint& aPosition,
  274. const wxPoint& aGridOrigin, wxRealPoint* aGridSize ) const
  275. {
  276. wxPoint pt;
  277. wxRealPoint gridSize;
  278. if( aGridSize )
  279. gridSize = *aGridSize;
  280. else
  281. gridSize = GetGridSize();
  282. double offset = fmod( aGridOrigin.x, gridSize.x );
  283. int x = KiROUND( (aPosition.x - offset) / gridSize.x );
  284. pt.x = KiROUND( x * gridSize.x + offset );
  285. offset = fmod( aGridOrigin.y, gridSize.y );
  286. int y = KiROUND( (aPosition.y - offset) / gridSize.y );
  287. pt.y = KiROUND ( y * gridSize.y + offset );
  288. return pt;
  289. }
  290. wxPoint BASE_SCREEN::getCursorPosition( bool aOnGrid, const wxPoint& aGridOrigin, wxRealPoint* aGridSize ) const
  291. {
  292. if( aOnGrid )
  293. return getNearestGridPosition( m_crossHairPosition, aGridOrigin, aGridSize );
  294. return m_crossHairPosition;
  295. }
  296. wxPoint BASE_SCREEN::getCrossHairScreenPosition() const
  297. {
  298. wxPoint pos = m_crossHairPosition - m_DrawOrg;
  299. double scalar = GetScalingFactor();
  300. pos.x = KiROUND( (double) pos.x * scalar );
  301. pos.y = KiROUND( (double) pos.y * scalar );
  302. return pos;
  303. }
  304. void BASE_SCREEN::setCrossHairPosition( const wxPoint& aPosition, const wxPoint& aGridOrigin, bool aSnapToGrid )
  305. {
  306. if( aSnapToGrid )
  307. m_crossHairPosition = getNearestGridPosition( aPosition, aGridOrigin, NULL );
  308. else
  309. m_crossHairPosition = aPosition;
  310. }
  311. void BASE_SCREEN::ClearUndoRedoList()
  312. {
  313. ClearUndoORRedoList( m_UndoList );
  314. ClearUndoORRedoList( m_RedoList );
  315. }
  316. void BASE_SCREEN::PushCommandToUndoList( PICKED_ITEMS_LIST* aNewitem )
  317. {
  318. m_UndoList.PushCommand( aNewitem );
  319. // Delete the extra items, if count max reached
  320. if( m_UndoRedoCountMax > 0 )
  321. {
  322. int extraitems = GetUndoCommandCount() - m_UndoRedoCountMax;
  323. if( extraitems > 0 )
  324. ClearUndoORRedoList( m_UndoList, extraitems );
  325. }
  326. }
  327. void BASE_SCREEN::PushCommandToRedoList( PICKED_ITEMS_LIST* aNewitem )
  328. {
  329. m_RedoList.PushCommand( aNewitem );
  330. // Delete the extra items, if count max reached
  331. if( m_UndoRedoCountMax > 0 )
  332. {
  333. int extraitems = GetRedoCommandCount() - m_UndoRedoCountMax;
  334. if( extraitems > 0 )
  335. ClearUndoORRedoList( m_RedoList, extraitems );
  336. }
  337. }
  338. PICKED_ITEMS_LIST* BASE_SCREEN::PopCommandFromUndoList( )
  339. {
  340. return m_UndoList.PopCommand( );
  341. }
  342. PICKED_ITEMS_LIST* BASE_SCREEN::PopCommandFromRedoList( )
  343. {
  344. return m_RedoList.PopCommand( );
  345. }
  346. #if defined(DEBUG)
  347. void BASE_SCREEN::Show( int nestLevel, std::ostream& os ) const
  348. {
  349. // for now, make it look like XML, expand on this later.
  350. NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str() << ">\n";
  351. /* this class will eventually go away, but here's a place holder until then.
  352. for( EDA_ITEM* item = m_drawList; item; item = item->Next() )
  353. {
  354. item->Show( nestLevel+1, os );
  355. }
  356. */
  357. NestedSpace( nestLevel, os ) << "</" << GetClass().Lower().mb_str() << ">\n";
  358. }
  359. #endif