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.

670 lines
20 KiB

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) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com
  5. * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.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. #ifndef PCB_DIMENSION_H
  25. #define PCB_DIMENSION_H
  26. #include <board_item.h>
  27. #include <pcb_text.h>
  28. #include <geometry/shape.h>
  29. #include <geometry/circle.h>
  30. class LINE_READER;
  31. class MSG_PANEL_ITEM;
  32. /// How to display the units in a dimension's text
  33. enum class DIM_UNITS_FORMAT
  34. {
  35. NO_SUFFIX, // 1234.0
  36. BARE_SUFFIX, // 1234.0 mm
  37. PAREN_SUFFIX // 1234.0 (mm)
  38. };
  39. enum class DIM_PRECISION
  40. {
  41. X = 0, // 0
  42. X_X, // 0.0
  43. X_XX, // 0.00
  44. X_XXX, // 0.000
  45. X_XXXX, // 0.0000
  46. X_XXXXX, // 0.00000
  47. V_VV, // 0.00 / 0 / 0.0
  48. V_VVV, // 0.000 / 0 / 0.00
  49. V_VVVV, // 0.0000 / 0.0 / 0.000
  50. V_VVVVV // 0.00000 / 0.00 / 0.0000
  51. };
  52. /// Where to place the text on a dimension
  53. enum class DIM_TEXT_POSITION
  54. {
  55. OUTSIDE, ///< Text appears outside the dimension line (default)
  56. INLINE, ///< Text appears in line with the dimension line
  57. MANUAL ///< Text placement is manually set by the user
  58. };
  59. /**
  60. * Used for storing the units selection in the file because EDA_UNITS alone doesn't cut it
  61. */
  62. enum class DIM_UNITS_MODE
  63. {
  64. INCHES,
  65. MILS,
  66. MILLIMETRES,
  67. AUTOMATIC
  68. };
  69. /**
  70. * Frame to show around dimension text
  71. */
  72. enum class DIM_TEXT_BORDER
  73. {
  74. NONE,
  75. RECTANGLE,
  76. CIRCLE,
  77. ROUNDRECT
  78. };
  79. /**
  80. * Abstract dimension API
  81. *
  82. * Some notes about dimension nomenclature:
  83. *
  84. * - "feature points" are the points being measured by the dimension. For an example, the start
  85. * and end points of a line to be measured. These are the first points picked when drawing a
  86. * new dimension. Dimensions can have one or more feature points: linear dimensions (the only
  87. * type supported in KiCad 5 and earlier) have two feature points; leader dimensions have one;
  88. * and ordinate dimensions can have in theory an unlimited number of feature points.
  89. *
  90. * - "feature lines" are lines that coincide with feature points. Not all dimension types have
  91. * feature lines. The actual start and end of feature lines is calculated from dimension style
  92. * properties (offset from feature point to start of feature line, height of crossbar, and height
  93. * of feature line past crossbar, for example in linear dimensions)
  94. *
  95. * - "crossbar" refers to the perpendicular line (usually with arrows at each end) between feature
  96. * lines on linear dimensions
  97. */
  98. class PCB_DIMENSION_BASE : public PCB_TEXT
  99. {
  100. public:
  101. PCB_DIMENSION_BASE( BOARD_ITEM* aParent, KICAD_T aType = PCB_DIMENSION_T );
  102. /**
  103. * The dimension's origin is the first feature point for the dimension. Every dimension has
  104. * one or more feature points, so every dimension has at least an origin.
  105. * @return the origin point of this dimension
  106. */
  107. virtual const VECTOR2I& GetStart() const { return m_start; }
  108. virtual void SetStart( const VECTOR2I& aPoint ) { m_start = aPoint; }
  109. virtual const VECTOR2I& GetEnd() const { return m_end; }
  110. virtual void SetEnd( const VECTOR2I& aPoint ) { m_end = aPoint; }
  111. VECTOR2I GetPosition() const override { return m_start; }
  112. void SetPosition( const VECTOR2I& aPos ) override { m_start = aPos; }
  113. bool GetOverrideTextEnabled() const { return m_overrideTextEnabled; }
  114. void SetOverrideTextEnabled( bool aOverride ) { m_overrideTextEnabled = aOverride; }
  115. wxString GetOverrideText() const { return m_valueString; }
  116. void SetOverrideText( const wxString& aValue ) { m_valueString = aValue; }
  117. void ChangeOverrideText( const wxString& aValue )
  118. {
  119. SetOverrideTextEnabled( true );
  120. SetOverrideText( aValue );
  121. updateText();
  122. }
  123. int GetMeasuredValue() const { return m_measuredValue; }
  124. // KiCad normally calculates the measured value but some importers need to set it.
  125. void SetMeasuredValue( int aValue ) { m_measuredValue = aValue; }
  126. /**
  127. * @return the dimension value, rendered with precision / zero suppression but no units, etc
  128. */
  129. wxString GetValueText() const;
  130. /**
  131. * Update the dimension's cached text and geometry.
  132. */
  133. void Update()
  134. {
  135. updateGeometry();
  136. updateText();
  137. }
  138. void UpdateUnits()
  139. {
  140. SetUnitsMode( GetUnitsMode() );
  141. updateText();
  142. }
  143. wxString GetPrefix() const { return m_prefix; }
  144. void SetPrefix( const wxString& aPrefix );
  145. void ChangePrefix( const wxString& aPrefix )
  146. {
  147. SetPrefix( aPrefix );
  148. updateText();
  149. }
  150. wxString GetSuffix() const { return m_suffix; }
  151. void SetSuffix( const wxString& aSuffix );
  152. void ChangeSuffix( const wxString& aSuffix )
  153. {
  154. SetSuffix( aSuffix );
  155. updateText();
  156. }
  157. EDA_UNITS GetUnits() const { return m_units; }
  158. void SetUnits( EDA_UNITS aUnits );
  159. DIM_UNITS_MODE GetUnitsMode() const;
  160. void SetUnitsMode( DIM_UNITS_MODE aMode );
  161. void ChangeUnitsMode( DIM_UNITS_MODE aMode )
  162. {
  163. SetUnitsMode( aMode );
  164. updateText();
  165. }
  166. void SetAutoUnits( bool aAuto = true ) { m_autoUnits = aAuto; }
  167. DIM_UNITS_FORMAT GetUnitsFormat() const { return m_unitsFormat; }
  168. void SetUnitsFormat( const DIM_UNITS_FORMAT aFormat ) { m_unitsFormat = aFormat; }
  169. void ChangeUnitsFormat( const DIM_UNITS_FORMAT aFormat )
  170. {
  171. SetUnitsFormat( aFormat );
  172. updateText();
  173. }
  174. DIM_PRECISION GetPrecision() const { return m_precision; }
  175. void SetPrecision( DIM_PRECISION aPrecision ) { m_precision = aPrecision; }
  176. void ChangePrecision( DIM_PRECISION aPrecision )
  177. {
  178. SetPrecision( aPrecision );
  179. updateText();
  180. }
  181. bool GetSuppressZeroes() const { return m_suppressZeroes; }
  182. void SetSuppressZeroes( bool aSuppress ) { m_suppressZeroes = aSuppress; }
  183. void ChangeSuppressZeroes( bool aSuppress )
  184. {
  185. SetSuppressZeroes( aSuppress );
  186. updateText();
  187. }
  188. bool GetKeepTextAligned() const { return m_keepTextAligned; }
  189. void SetKeepTextAligned( bool aKeepAligned ) { m_keepTextAligned = aKeepAligned; }
  190. void SetTextPositionMode( DIM_TEXT_POSITION aMode ) { m_textPosition = aMode; }
  191. DIM_TEXT_POSITION GetTextPositionMode() const { return m_textPosition; }
  192. int GetArrowLength() const { return m_arrowLength; }
  193. void SetArrowLength( int aLength ) { m_arrowLength = aLength; }
  194. void SetExtensionOffset( int aOffset ) { m_extensionOffset = aOffset; }
  195. int GetExtensionOffset() const { return m_extensionOffset; }
  196. int GetLineThickness() const { return m_lineThickness; }
  197. void SetLineThickness( int aWidth ) { m_lineThickness = aWidth; }
  198. /**
  199. * @return a list of line segments that make up this dimension (for drawing, plotting, etc).
  200. */
  201. const std::vector<std::shared_ptr<SHAPE>>& GetShapes() const { return m_shapes; }
  202. // BOARD_ITEM overrides
  203. void Move( const VECTOR2I& offset ) override;
  204. void Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle ) override;
  205. void Flip( const VECTOR2I& aCentre, bool aFlipLeftRight ) override;
  206. /**
  207. * Mirror the dimension relative to a given horizontal axis.
  208. *
  209. * The text is not mirrored. Only its position (and angle) is mirrored. The layer is not
  210. * changed.
  211. *
  212. * @param axis_pos is the vertical axis position to mirror around.
  213. */
  214. virtual void Mirror( const VECTOR2I& axis_pos, bool aMirrorLeftRight = false );
  215. void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override;
  216. bool HitTest( const VECTOR2I& aPosition, int aAccuracy ) const override;
  217. bool HitTest( const BOX2I& aRect, bool aContained, int aAccuracy = 0 ) const override;
  218. const BOX2I GetBoundingBox() const override;
  219. std::shared_ptr<SHAPE> GetEffectiveShape( PCB_LAYER_ID aLayer,
  220. FLASHING aFlash = FLASHING::DEFAULT ) const override;
  221. wxString GetItemDescription( UNITS_PROVIDER* aUnitsProvider ) const override;
  222. const BOX2I ViewBBox() const override;
  223. void ClearRenderCache() override;
  224. void TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer, int aClearance,
  225. int aError, ERROR_LOC aErrorLoc,
  226. bool aIgnoreLineWidth = false ) const override;
  227. double Similarity( const BOARD_ITEM& aOther ) const override;
  228. bool operator==( const BOARD_ITEM& aOther ) const override;
  229. #if defined(DEBUG)
  230. virtual void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); }
  231. #endif
  232. protected:
  233. /**
  234. * Update the cached geometry of the dimension after changing any of its properties.
  235. */
  236. virtual void updateGeometry() = 0;
  237. /**
  238. * Update the text field value from the current geometry (called by updateGeometry normally).
  239. */
  240. virtual void updateText();
  241. template<typename ShapeType>
  242. void addShape( const ShapeType& aShape );
  243. /**
  244. * Find the intersection between a given segment and polygon outline.
  245. *
  246. * @param aPoly is the polygon to collide.
  247. * @param aSeg is the segment to collide.
  248. * @param aStart if true will start from aSeg.A, otherwise aSeg.B.
  249. * @return a point on aSeg that collides with aPoly closest to the start, if one exists.
  250. */
  251. static OPT_VECTOR2I segPolyIntersection( const SHAPE_POLY_SET& aPoly, const SEG& aSeg,
  252. bool aStart = true );
  253. static OPT_VECTOR2I segCircleIntersection( CIRCLE& aCircle, SEG& aSeg, bool aStart = true );
  254. // Value format
  255. bool m_overrideTextEnabled; ///< Manually specify the displayed measurement value
  256. wxString m_valueString; ///< Displayed value when m_overrideValue = true
  257. wxString m_prefix; ///< String prepended to the value
  258. wxString m_suffix; ///< String appended to the value
  259. EDA_UNITS m_units; ///< 0 = inches, 1 = mm
  260. bool m_autoUnits; ///< If true, follow the currently selected UI units
  261. DIM_UNITS_FORMAT m_unitsFormat; ///< How to render the units suffix
  262. DIM_PRECISION m_precision; ///< Number of digits to display after decimal
  263. bool m_suppressZeroes; ///< Suppress trailing zeroes
  264. // Geometry
  265. int m_lineThickness; ///< Thickness used for all graphics in the dimension
  266. int m_arrowLength; ///< Length of arrow shapes
  267. int m_extensionOffset; ///< Distance from feature points to extension line start
  268. DIM_TEXT_POSITION m_textPosition; ///< How to position the text
  269. bool m_keepTextAligned; ///< Calculate text orientation to match dimension
  270. // Internal
  271. int m_measuredValue; ///< value of PCB dimensions
  272. VECTOR2I m_start;
  273. VECTOR2I m_end;
  274. ///< Internal cache of drawn shapes
  275. std::vector<std::shared_ptr<SHAPE>> m_shapes;
  276. bool m_inClearRenderCache; ///< re-entrancy guard
  277. };
  278. /**
  279. * For better understanding of the points that make a dimension:
  280. *
  281. * Note: historically KiCad called extension lines "feature lines", and also note that what we
  282. * call the "crossbar line" here is more commonly called the "dimension line"
  283. *
  284. * Start (feature point 1) End (feature point 2)
  285. * | |
  286. * | <-- extension lines --> |
  287. * | |
  288. * | m_arrowG2F m_arrowD2F |
  289. * | / \ |
  290. * Crossbar start |/_______crossbar line________\| Crossbar end
  291. * |\ m_text /|
  292. * | \ / |
  293. * | m_arrowG1F m_arrowD1F |
  294. * | |
  295. * m_featureLineGF m_featureLineDF
  296. */
  297. /**
  298. * An aligned dimension measures the distance between two feature points. It has a crossbar
  299. * (dimension line) that stays parallel with the vector between the feature points.
  300. *
  301. * The height (distance from features to crossbar) can be set directly, or set by manipulating the
  302. * crossbar start or end point (with the point editor).
  303. */
  304. class PCB_DIM_ALIGNED : public PCB_DIMENSION_BASE
  305. {
  306. public:
  307. PCB_DIM_ALIGNED( BOARD_ITEM* aParent, KICAD_T aType = PCB_DIM_ALIGNED_T );
  308. // Do not create a copy constructor & operator=.
  309. // The ones generated by the compiler are adequate.
  310. ~PCB_DIM_ALIGNED() = default;
  311. static inline bool ClassOf( const EDA_ITEM* aItem )
  312. {
  313. return aItem && aItem->Type() == PCB_DIM_ALIGNED_T;
  314. }
  315. EDA_ITEM* Clone() const override;
  316. void Mirror( const VECTOR2I& axis_pos, bool aMirrorLeftRight = false ) override;
  317. BITMAPS GetMenuImage() const override;
  318. const VECTOR2I& GetCrossbarStart() const { return m_crossBarStart; }
  319. const VECTOR2I& GetCrossbarEnd() const { return m_crossBarEnd; }
  320. /**
  321. * Set the distance from the feature points to the crossbar line.
  322. *
  323. * @param aHeight is the new height.
  324. */
  325. void SetHeight( int aHeight ) { m_height = aHeight; }
  326. int GetHeight() const { return m_height; }
  327. void ChangeHeight( int aHeight )
  328. {
  329. SetHeight( aHeight );
  330. updateGeometry();
  331. }
  332. /**
  333. * Update the stored height basing on points coordinates.
  334. *
  335. * @param aCrossbarStart is the start point of the crossbar.
  336. */
  337. void UpdateHeight( const VECTOR2I& aCrossbarStart, const VECTOR2I& aCrossbarEnd );
  338. void SetExtensionHeight( int aHeight ) { m_extensionHeight = aHeight; }
  339. int GetExtensionHeight() const { return m_extensionHeight; }
  340. void ChangeExtensionHeight( int aHeight )
  341. {
  342. SetExtensionHeight( aHeight );
  343. updateGeometry();
  344. }
  345. /**
  346. * Return the angle of the crossbar.
  347. *
  348. * @return Angle of the crossbar line expressed in radians.
  349. */
  350. double GetAngle() const
  351. {
  352. VECTOR2I delta( m_end - m_start );
  353. return atan2( (double)delta.y, (double)delta.x );
  354. }
  355. wxString GetClass() const override
  356. {
  357. return wxT( "PCB_DIM_ALIGNED" );
  358. }
  359. void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override;
  360. protected:
  361. virtual void swapData( BOARD_ITEM* aImage ) override;
  362. void updateGeometry() override;
  363. void updateText() override;
  364. // Geometry
  365. int m_height; ///< Perpendicular distance from features to crossbar
  366. int m_extensionHeight; ///< Length of extension lines past the crossbar
  367. VECTOR2I m_crossBarStart; ///< Crossbar start control point
  368. VECTOR2I m_crossBarEnd; ///< Crossbar end control point
  369. };
  370. /**
  371. * An orthogonal dimension is like an aligned dimension, but the extension lines are locked to the
  372. * X or Y axes, and the measurement is only taken in the X or Y direction.
  373. */
  374. class PCB_DIM_ORTHOGONAL : public PCB_DIM_ALIGNED
  375. {
  376. public:
  377. enum class DIR
  378. {
  379. HORIZONTAL, // Aligned with x-axis
  380. VERTICAL // Aligned with y-axis
  381. };
  382. PCB_DIM_ORTHOGONAL( BOARD_ITEM* aParent );
  383. ~PCB_DIM_ORTHOGONAL() = default;
  384. static inline bool ClassOf( const EDA_ITEM* aItem )
  385. {
  386. return aItem && aItem->Type() == PCB_DIM_ORTHOGONAL_T;
  387. }
  388. EDA_ITEM* Clone() const override;
  389. BITMAPS GetMenuImage() const override;
  390. /**
  391. * Set the orientation of the dimension line (so, perpendicular to the feature lines).
  392. *
  393. * @param aOrientation is the orientation the dimension should take.
  394. */
  395. void SetOrientation( DIR aOrientation ) { m_orientation = aOrientation; }
  396. DIR GetOrientation() const { return m_orientation; }
  397. wxString GetClass() const override
  398. {
  399. return wxT( "PCB_DIM_ORTHOGONAL" );
  400. }
  401. void Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle ) override;
  402. protected:
  403. void swapData( BOARD_ITEM* aImage ) override;
  404. void updateGeometry() override;
  405. void updateText() override;
  406. private:
  407. // Geometry
  408. DIR m_orientation; ///< What axis to lock the dimension line to.
  409. };
  410. /**
  411. * A radial dimension indicates either the radius or diameter of an arc or circle.
  412. *
  413. * A guide to the geometry of a circle dimension:
  414. *
  415. * |
  416. * --a--
  417. * |
  418. *
  419. *
  420. * b_
  421. * |\
  422. * \
  423. * c---d TEXT
  424. *
  425. * Point a (the center of the arc or circle) is m_start, point b (a point on the arc or circle)
  426. * is m_end, point c is m_leaderLength away from b on the a-b vector, and point d is the end of
  427. * the "text line". The c-d line is drawn from c to the text center, and clipped on the text
  428. * bounding box.
  429. */
  430. class PCB_DIM_RADIAL : public PCB_DIMENSION_BASE
  431. {
  432. public:
  433. PCB_DIM_RADIAL( BOARD_ITEM* aParent );
  434. static inline bool ClassOf( const EDA_ITEM* aItem )
  435. {
  436. return aItem && aItem->Type() == PCB_DIM_RADIAL_T;
  437. }
  438. EDA_ITEM* Clone() const override;
  439. void SetLeaderLength( int aLength ) { m_leaderLength = aLength; }
  440. int GetLeaderLength() const { return m_leaderLength; }
  441. void ChangeLeaderLength( int aLength )
  442. {
  443. SetLeaderLength( aLength );
  444. updateGeometry();
  445. }
  446. // Returns the point (c).
  447. VECTOR2I GetKnee() const;
  448. BITMAPS GetMenuImage() const override;
  449. wxString GetClass() const override
  450. {
  451. return wxT( "PCB_DIM_RADIAL" );
  452. }
  453. protected:
  454. virtual void swapData( BOARD_ITEM* aImage ) override;
  455. void updateText() override;
  456. void updateGeometry() override;
  457. private:
  458. bool m_isDiameter;
  459. int m_leaderLength;
  460. };
  461. /**
  462. * A leader is a dimension-like object pointing to a specific point.
  463. *
  464. * A guide to the geometry of a leader:
  465. *
  466. * a_
  467. * |\
  468. * \
  469. * b---c TEXT
  470. *
  471. * Point (a) is m_start, point (b) is m_end, point (c) is the end of the "text line"
  472. * The b-c line is drawn from b to the text center, and clipped on the text bounding box.
  473. */
  474. class PCB_DIM_LEADER : public PCB_DIMENSION_BASE
  475. {
  476. public:
  477. PCB_DIM_LEADER( BOARD_ITEM* aParent );
  478. static inline bool ClassOf( const EDA_ITEM* aItem )
  479. {
  480. return aItem && aItem->Type() == PCB_DIM_LEADER_T;
  481. }
  482. EDA_ITEM* Clone() const override;
  483. BITMAPS GetMenuImage() const override;
  484. wxString GetClass() const override
  485. {
  486. return wxT( "PCB_DIM_LEADER" );
  487. }
  488. void SetTextBorder( DIM_TEXT_BORDER aBorder ) { m_textBorder = aBorder; }
  489. DIM_TEXT_BORDER GetTextBorder() const { return m_textBorder; }
  490. void ChangeTextBorder( DIM_TEXT_BORDER aBorder )
  491. {
  492. SetTextBorder( aBorder );
  493. updateGeometry();
  494. }
  495. void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override;
  496. protected:
  497. virtual void swapData( BOARD_ITEM* aImage ) override;
  498. void updateText() override;
  499. void updateGeometry() override;
  500. private:
  501. DIM_TEXT_BORDER m_textBorder;
  502. };
  503. /**
  504. * Mark the center of a circle or arc with a cross shape.
  505. *
  506. * The size and orientation of the cross is adjustable.
  507. * m_start always marks the center being measured; m_end marks the end of one leg of the cross.
  508. */
  509. class PCB_DIM_CENTER : public PCB_DIMENSION_BASE
  510. {
  511. public:
  512. PCB_DIM_CENTER( BOARD_ITEM* aParent );
  513. static inline bool ClassOf( const EDA_ITEM* aItem )
  514. {
  515. return aItem && aItem->Type() == PCB_DIM_CENTER_T;
  516. }
  517. EDA_ITEM* Clone() const override;
  518. BITMAPS GetMenuImage() const override;
  519. wxString GetClass() const override
  520. {
  521. return wxT( "PCB_DIM_CENTER" );
  522. }
  523. const BOX2I GetBoundingBox() const override;
  524. const BOX2I ViewBBox() const override;
  525. protected:
  526. virtual void swapData( BOARD_ITEM* aImage ) override;
  527. void updateGeometry() override;
  528. };
  529. #endif // DIMENSION_H