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