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.

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