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.

520 lines
15 KiB

14 years ago
14 years ago
14 years ago
14 years ago
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) 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 class_dimension.cpp
  28. */
  29. #include <fctsys.h>
  30. #include <macros.h>
  31. #include <gr_basic.h>
  32. #include <trigo.h>
  33. #include <class_drawpanel.h>
  34. #include <kicad_string.h>
  35. #include <richio.h>
  36. #include <bitmaps.h>
  37. #include <pcb_edit_frame.h>
  38. #include <class_board.h>
  39. #include <class_pcb_text.h>
  40. #include <class_dimension.h>
  41. #include <base_units.h>
  42. DIMENSION::DIMENSION( BOARD_ITEM* aParent ) :
  43. BOARD_ITEM( aParent, PCB_DIMENSION_T ),
  44. m_Width( Millimeter2iu( 0.2 ) ),
  45. m_Unit( INCHES ),
  46. m_UseMils( false ),
  47. m_Value( 0 ),
  48. m_Height( 0 ),
  49. m_Text( this )
  50. {
  51. m_Layer = Dwgs_User;
  52. m_Shape = 0;
  53. }
  54. DIMENSION::~DIMENSION()
  55. {
  56. }
  57. void DIMENSION::SetPosition( const wxPoint& aPos )
  58. {
  59. m_Text.SetTextPos( aPos );
  60. }
  61. const wxPoint DIMENSION::GetPosition() const
  62. {
  63. return m_Text.GetTextPos();
  64. }
  65. void DIMENSION::SetText( const wxString& aNewText )
  66. {
  67. m_Text.SetText( aNewText );
  68. }
  69. const wxString DIMENSION::GetText() const
  70. {
  71. return m_Text.GetText();
  72. }
  73. void DIMENSION::SetLayer( PCB_LAYER_ID aLayer )
  74. {
  75. m_Layer = aLayer;
  76. m_Text.SetLayer( aLayer );
  77. }
  78. void DIMENSION::Move( const wxPoint& offset )
  79. {
  80. m_Text.Offset( offset );
  81. m_crossBarO += offset;
  82. m_crossBarF += offset;
  83. m_featureLineGO += offset;
  84. m_featureLineGF += offset;
  85. m_featureLineDO += offset;
  86. m_featureLineDF += offset;
  87. m_arrowG1F += offset;
  88. m_arrowG2F += offset;
  89. m_arrowD1F += offset;
  90. m_arrowD2F += offset;
  91. }
  92. void DIMENSION::Rotate( const wxPoint& aRotCentre, double aAngle )
  93. {
  94. wxPoint tmp = m_Text.GetTextPos();
  95. RotatePoint( &tmp, aRotCentre, aAngle );
  96. m_Text.SetTextPos( tmp );
  97. double newAngle = m_Text.GetTextAngle() + aAngle;
  98. if( newAngle >= 3600 )
  99. newAngle -= 3600;
  100. if( newAngle > 900 && newAngle < 2700 )
  101. newAngle -= 1800;
  102. m_Text.SetTextAngle( newAngle );
  103. RotatePoint( &m_crossBarO, aRotCentre, aAngle );
  104. RotatePoint( &m_crossBarF, aRotCentre, aAngle );
  105. RotatePoint( &m_featureLineGO, aRotCentre, aAngle );
  106. RotatePoint( &m_featureLineGF, aRotCentre, aAngle );
  107. RotatePoint( &m_featureLineDO, aRotCentre, aAngle );
  108. RotatePoint( &m_featureLineDF, aRotCentre, aAngle );
  109. RotatePoint( &m_arrowG1F, aRotCentre, aAngle );
  110. RotatePoint( &m_arrowG2F, aRotCentre, aAngle );
  111. RotatePoint( &m_arrowD1F, aRotCentre, aAngle );
  112. RotatePoint( &m_arrowD2F, aRotCentre, aAngle );
  113. }
  114. void DIMENSION::Flip( const wxPoint& aCentre )
  115. {
  116. Mirror( aCentre );
  117. // DIMENSION items are not usually on copper layers, so
  118. // copper layers count is not taken in accoun in Flip transform
  119. SetLayer( FlipLayer( GetLayer() ) );
  120. }
  121. void DIMENSION::Mirror( const wxPoint& axis_pos )
  122. {
  123. wxPoint newPos = m_Text.GetTextPos();
  124. #define INVERT( pos ) (pos) = axis_pos.y - ( (pos) - axis_pos.y )
  125. INVERT( newPos.y );
  126. m_Text.SetTextPos( newPos );
  127. // invert angle
  128. m_Text.SetTextAngle( -m_Text.GetTextAngle() );
  129. INVERT( m_crossBarO.y );
  130. INVERT( m_crossBarF.y );
  131. INVERT( m_featureLineGO.y );
  132. INVERT( m_featureLineGF.y );
  133. INVERT( m_featureLineDO.y );
  134. INVERT( m_featureLineDF.y );
  135. INVERT( m_arrowG1F.y );
  136. INVERT( m_arrowG2F.y );
  137. INVERT( m_arrowD1F.y );
  138. INVERT( m_arrowD2F.y );
  139. }
  140. void DIMENSION::SetOrigin( const wxPoint& aOrigin )
  141. {
  142. m_featureLineGO = aOrigin;
  143. AdjustDimensionDetails();
  144. }
  145. void DIMENSION::SetEnd( const wxPoint& aEnd )
  146. {
  147. m_featureLineDO = aEnd;
  148. AdjustDimensionDetails();
  149. }
  150. void DIMENSION::SetHeight( int aHeight )
  151. {
  152. m_Height = aHeight;
  153. AdjustDimensionDetails();
  154. }
  155. void DIMENSION::UpdateHeight()
  156. {
  157. VECTOR2D featureLine( m_crossBarO - m_featureLineGO );
  158. VECTOR2D crossBar( m_featureLineDO - m_featureLineGO );
  159. if( featureLine.Cross( crossBar ) > 0 )
  160. m_Height = -featureLine.EuclideanNorm();
  161. else
  162. m_Height = featureLine.EuclideanNorm();
  163. }
  164. void DIMENSION::AdjustDimensionDetails()
  165. {
  166. const int arrowz = Mils2iu( 50 ); // size of arrows
  167. int ii;
  168. int measure, deltax, deltay; // value of the measure on X and Y axes
  169. int arrow_up_X = 0, arrow_up_Y = 0; // coordinates of arrow line /
  170. int arrow_dw_X = 0, arrow_dw_Y = 0; // coordinates of arrow line '\'
  171. int hx, hy; // dimension line interval
  172. double angle, angle_f;
  173. // Init layer :
  174. m_Text.SetLayer( GetLayer() );
  175. // calculate the size of the dimension (text + line above the text)
  176. ii = m_Text.GetTextHeight() + m_Text.GetThickness() + ( m_Width );
  177. deltax = m_featureLineDO.x - m_featureLineGO.x;
  178. deltay = m_featureLineDO.y - m_featureLineGO.y;
  179. // Calculate dimension value
  180. measure = KiROUND( hypot( deltax, deltay ) );
  181. angle = atan2( (double)deltay, (double)deltax );
  182. // Calculation of parameters X and Y dimensions of the arrows and lines.
  183. hx = hy = ii;
  184. // Taking into account the slope of the side lines.
  185. if( measure )
  186. {
  187. hx = abs( KiROUND( ( (double) deltay * hx ) / measure ) );
  188. hy = abs( KiROUND( ( (double) deltax * hy ) / measure ) );
  189. if( m_featureLineGO.x > m_crossBarO.x )
  190. hx = -hx;
  191. if( m_featureLineGO.x == m_crossBarO.x )
  192. hx = 0;
  193. if( m_featureLineGO.y > m_crossBarO.y )
  194. hy = -hy;
  195. if( m_featureLineGO.y == m_crossBarO.y )
  196. hy = 0;
  197. angle_f = angle + DEG2RAD( 27.5 );
  198. arrow_up_X = wxRound( arrowz * cos( angle_f ) );
  199. arrow_up_Y = wxRound( arrowz * sin( angle_f ) );
  200. angle_f = angle - DEG2RAD( 27.5 );
  201. arrow_dw_X = wxRound( arrowz * cos( angle_f ) );
  202. arrow_dw_Y = wxRound( arrowz * sin( angle_f ) );
  203. }
  204. int dx = KiROUND( m_Height * cos( angle + M_PI / 2 ) );
  205. int dy = KiROUND( m_Height * sin( angle + M_PI / 2 ) );
  206. m_crossBarO.x = m_featureLineGO.x + dx;
  207. m_crossBarO.y = m_featureLineGO.y + dy;
  208. m_crossBarF.x = m_featureLineDO.x + dx;
  209. m_crossBarF.y = m_featureLineDO.y + dy;
  210. m_arrowG1F.x = m_crossBarO.x + arrow_up_X;
  211. m_arrowG1F.y = m_crossBarO.y + arrow_up_Y;
  212. m_arrowG2F.x = m_crossBarO.x + arrow_dw_X;
  213. m_arrowG2F.y = m_crossBarO.y + arrow_dw_Y;
  214. /* The right arrow is symmetrical to the left.
  215. * / = -\ and \ = -/
  216. */
  217. m_arrowD1F.x = m_crossBarF.x - arrow_dw_X;
  218. m_arrowD1F.y = m_crossBarF.y - arrow_dw_Y;
  219. m_arrowD2F.x = m_crossBarF.x - arrow_up_X;
  220. m_arrowD2F.y = m_crossBarF.y - arrow_up_Y;
  221. // Length of feature lines
  222. double radius = ( m_Height +
  223. ( std::copysign( 1.0, m_Height ) *
  224. arrowz * sin( DEG2RAD( 27.5 ) ) ) );
  225. m_featureLineGF.x = m_featureLineGO.x - wxRound( radius * sin( angle ) );
  226. m_featureLineGF.y = m_featureLineGO.y + wxRound( radius * cos( angle ) );
  227. m_featureLineDF.x = m_featureLineDO.x - wxRound( radius * sin( angle ) );
  228. m_featureLineDF.y = m_featureLineDO.y + wxRound( radius * cos( angle ) );
  229. // Calculate the better text position and orientation:
  230. radius = ( std::copysign( 1.0, m_Height ) * ii );
  231. wxPoint textPos;
  232. textPos.x = ( m_crossBarF.x + m_crossBarO.x ) / 2;
  233. textPos.y = ( m_crossBarF.y + m_crossBarO.y ) / 2;
  234. textPos.x -= KiROUND( radius * sin( angle ) );
  235. textPos.y += KiROUND( radius * cos( angle ) );
  236. m_Text.SetTextPos( textPos );
  237. double newAngle = -RAD2DECIDEG( angle );
  238. NORMALIZE_ANGLE_POS( newAngle );
  239. if( newAngle > 900 && newAngle < 2700 )
  240. newAngle -= 1800;
  241. m_Text.SetTextAngle( newAngle );
  242. m_Value = measure;
  243. SetText( MessageTextFromValue( m_Unit, m_Value, m_UseMils ) );
  244. }
  245. void DIMENSION::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE mode_color,
  246. const wxPoint& offset )
  247. {
  248. BOARD* brd = GetBoard();
  249. if( brd->IsLayerVisible( m_Layer ) == false )
  250. return;
  251. m_Text.Draw( panel, DC, mode_color, offset );
  252. auto frame = static_cast<PCB_EDIT_FRAME*> ( panel->GetParent() );
  253. auto gcolor = frame->Settings().Colors().GetLayerColor( m_Layer );
  254. GRSetDrawMode( DC, mode_color );
  255. auto displ_opts = (PCB_DISPLAY_OPTIONS*)( panel->GetDisplayOptions() );
  256. bool filled = displ_opts ? displ_opts->m_DisplayDrawItemsFill : FILLED;
  257. int width = m_Width;
  258. if( filled )
  259. {
  260. GRLine( panel->GetClipBox(), DC, m_crossBarO + offset,
  261. m_crossBarF + offset, width, gcolor );
  262. GRLine( panel->GetClipBox(), DC, m_featureLineGO + offset,
  263. m_featureLineGF + offset, width, gcolor );
  264. GRLine( panel->GetClipBox(), DC, m_featureLineDO + offset,
  265. m_featureLineDF + offset, width, gcolor );
  266. GRLine( panel->GetClipBox(), DC, m_crossBarF + offset,
  267. m_arrowD1F + offset, width, gcolor );
  268. GRLine( panel->GetClipBox(), DC, m_crossBarF + offset,
  269. m_arrowD2F + offset, width, gcolor );
  270. GRLine( panel->GetClipBox(), DC, m_crossBarO + offset,
  271. m_arrowG1F + offset, width, gcolor );
  272. GRLine( panel->GetClipBox(), DC, m_crossBarO + offset,
  273. m_arrowG2F + offset, width, gcolor );
  274. }
  275. else
  276. {
  277. GRCSegm( panel->GetClipBox(), DC, m_crossBarO + offset,
  278. m_crossBarF + offset, width, gcolor );
  279. GRCSegm( panel->GetClipBox(), DC, m_featureLineGO + offset,
  280. m_featureLineGF + offset, width, gcolor );
  281. GRCSegm( panel->GetClipBox(), DC, m_featureLineDO + offset,
  282. m_featureLineDF + offset, width, gcolor );
  283. GRCSegm( panel->GetClipBox(), DC, m_crossBarF + offset,
  284. m_arrowD1F + offset, width, gcolor );
  285. GRCSegm( panel->GetClipBox(), DC, m_crossBarF + offset,
  286. m_arrowD2F + offset, width, gcolor );
  287. GRCSegm( panel->GetClipBox(), DC, m_crossBarO + offset,
  288. m_arrowG1F + offset, width, gcolor );
  289. GRCSegm( panel->GetClipBox(), DC, m_crossBarO + offset,
  290. m_arrowG2F + offset, width, gcolor );
  291. }
  292. }
  293. // see class_cotation.h
  294. void DIMENSION::GetMsgPanelInfo( EDA_UNITS_T aUnits, std::vector< MSG_PANEL_ITEM >& aList )
  295. {
  296. // for now, display only the text within the DIMENSION using class TEXTE_PCB.
  297. m_Text.GetMsgPanelInfo( aUnits, aList );
  298. }
  299. bool DIMENSION::HitTest( const wxPoint& aPosition ) const
  300. {
  301. if( m_Text.TextHitTest( aPosition ) )
  302. return true;
  303. int dist_max = m_Width / 2;
  304. // Locate SEGMENTS
  305. if( TestSegmentHit( aPosition, m_crossBarO, m_crossBarF, dist_max ) )
  306. return true;
  307. if( TestSegmentHit( aPosition, m_featureLineGO, m_featureLineGF, dist_max ) )
  308. return true;
  309. if( TestSegmentHit( aPosition, m_featureLineDO, m_featureLineDF, dist_max ) )
  310. return true;
  311. if( TestSegmentHit( aPosition, m_crossBarF, m_arrowD1F, dist_max ) )
  312. return true;
  313. if( TestSegmentHit( aPosition, m_crossBarF, m_arrowD2F, dist_max ) )
  314. return true;
  315. if( TestSegmentHit( aPosition, m_crossBarO, m_arrowG1F, dist_max ) )
  316. return true;
  317. if( TestSegmentHit( aPosition, m_crossBarO, m_arrowG2F, dist_max ) )
  318. return true;
  319. return false;
  320. }
  321. bool DIMENSION::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
  322. {
  323. EDA_RECT arect = aRect;
  324. arect.Inflate( aAccuracy );
  325. EDA_RECT rect = GetBoundingBox();
  326. if( aAccuracy )
  327. rect.Inflate( aAccuracy );
  328. if( aContained )
  329. return arect.Contains( rect );
  330. return arect.Intersects( rect );
  331. }
  332. const EDA_RECT DIMENSION::GetBoundingBox() const
  333. {
  334. EDA_RECT bBox;
  335. int xmin, xmax, ymin, ymax;
  336. bBox = m_Text.GetTextBox( -1 );
  337. xmin = bBox.GetX();
  338. xmax = bBox.GetRight();
  339. ymin = bBox.GetY();
  340. ymax = bBox.GetBottom();
  341. xmin = std::min( xmin, m_crossBarO.x );
  342. xmin = std::min( xmin, m_crossBarF.x );
  343. ymin = std::min( ymin, m_crossBarO.y );
  344. ymin = std::min( ymin, m_crossBarF.y );
  345. xmax = std::max( xmax, m_crossBarO.x );
  346. xmax = std::max( xmax, m_crossBarF.x );
  347. ymax = std::max( ymax, m_crossBarO.y );
  348. ymax = std::max( ymax, m_crossBarF.y );
  349. xmin = std::min( xmin, m_featureLineGO.x );
  350. xmin = std::min( xmin, m_featureLineGF.x );
  351. ymin = std::min( ymin, m_featureLineGO.y );
  352. ymin = std::min( ymin, m_featureLineGF.y );
  353. xmax = std::max( xmax, m_featureLineGO.x );
  354. xmax = std::max( xmax, m_featureLineGF.x );
  355. ymax = std::max( ymax, m_featureLineGO.y );
  356. ymax = std::max( ymax, m_featureLineGF.y );
  357. xmin = std::min( xmin, m_featureLineDO.x );
  358. xmin = std::min( xmin, m_featureLineDF.x );
  359. ymin = std::min( ymin, m_featureLineDO.y );
  360. ymin = std::min( ymin, m_featureLineDF.y );
  361. xmax = std::max( xmax, m_featureLineDO.x );
  362. xmax = std::max( xmax, m_featureLineDF.x );
  363. ymax = std::max( ymax, m_featureLineDO.y );
  364. ymax = std::max( ymax, m_featureLineDF.y );
  365. bBox.SetX( xmin );
  366. bBox.SetY( ymin );
  367. bBox.SetWidth( xmax - xmin + 1 );
  368. bBox.SetHeight( ymax - ymin + 1 );
  369. bBox.Normalize();
  370. return bBox;
  371. }
  372. wxString DIMENSION::GetSelectMenuText( EDA_UNITS_T aUnits ) const
  373. {
  374. return wxString::Format( _( "Dimension \"%s\" on %s" ), GetText(), GetLayerName() );
  375. }
  376. BITMAP_DEF DIMENSION::GetMenuImage() const
  377. {
  378. return add_dimension_xpm;
  379. }
  380. const BOX2I DIMENSION::ViewBBox() const
  381. {
  382. BOX2I dimBBox = BOX2I( VECTOR2I( GetBoundingBox().GetPosition() ),
  383. VECTOR2I( GetBoundingBox().GetSize() ) );
  384. dimBBox.Merge( m_Text.ViewBBox() );
  385. return dimBBox;
  386. }
  387. EDA_ITEM* DIMENSION::Clone() const
  388. {
  389. return new DIMENSION( *this );
  390. }
  391. void DIMENSION::SwapData( BOARD_ITEM* aImage )
  392. {
  393. assert( aImage->Type() == PCB_DIMENSION_T );
  394. std::swap( *((DIMENSION*) this), *((DIMENSION*) aImage) );
  395. }