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.

524 lines
16 KiB

4 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2018 Jean-Pierre Charras jp.charras at wanadoo.fr
  5. * Copyright The 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. #pragma once
  25. #include <core/mirror.h>
  26. #include <geometry/shape_poly_set.h>
  27. #include <geometry/approximation.h>
  28. #include <properties/property.h>
  29. #include <stroke_params.h>
  30. #include <trigo.h>
  31. #include <api/serializable.h>
  32. class LINE_READER;
  33. class EDA_DRAW_FRAME;
  34. class FOOTPRINT;
  35. class MSG_PANEL_ITEM;
  36. using KIGFX::COLOR4D;
  37. enum class SHAPE_T : int
  38. {
  39. UNDEFINED = -1,
  40. SEGMENT = 0,
  41. RECTANGLE, ///< Use RECTANGLE instead of RECT to avoid collision in a Windows header.
  42. ARC,
  43. CIRCLE,
  44. POLY,
  45. BEZIER
  46. };
  47. // WARNING: Do not change these values without updating dialogs that depend on their position values
  48. enum class FILL_T : int
  49. {
  50. NO_FILL = 1,
  51. FILLED_SHAPE, ///< Fill with object color.
  52. FILLED_WITH_BG_BODYCOLOR, //< Fill with background body color.
  53. FILLED_WITH_COLOR, //< Fill with a separate color.
  54. HATCH,
  55. REVERSE_HATCH,
  56. CROSS_HATCH
  57. };
  58. enum UI_FILL_MODE
  59. {
  60. NONE = 0,
  61. SOLID,
  62. HATCH,
  63. REVERSE_HATCH,
  64. CROSS_HATCH
  65. };
  66. /// Holding struct to keep originating midpoint
  67. struct ARC_MID
  68. {
  69. VECTOR2I mid;
  70. VECTOR2I start;
  71. VECTOR2I end;
  72. VECTOR2I center;
  73. };
  74. class EDA_SHAPE : public SERIALIZABLE
  75. {
  76. public:
  77. EDA_SHAPE( SHAPE_T aType, int aLineWidth, FILL_T aFill );
  78. /// Construct an EDA_SHAPE from an abstract SHAPE geometry.
  79. EDA_SHAPE( const SHAPE& aShape );
  80. // Do not create a copy constructor & operator=.
  81. // The ones generated by the compiler are adequate.
  82. virtual ~EDA_SHAPE();
  83. void SwapShape( EDA_SHAPE* aImage );
  84. void Serialize( google::protobuf::Any &aContainer ) const override;
  85. bool Deserialize( const google::protobuf::Any &aContainer ) override;
  86. wxString ShowShape() const;
  87. wxString SHAPE_T_asString() const;
  88. virtual bool IsProxyItem() const { return m_proxyItem; }
  89. virtual void SetIsProxyItem( bool aIsProxy = true ) { m_proxyItem = aIsProxy; }
  90. bool IsAnyFill() const
  91. {
  92. return GetFillMode() != FILL_T::NO_FILL;
  93. }
  94. bool IsSolidFill() const
  95. {
  96. return GetFillMode() == FILL_T::FILLED_SHAPE
  97. || GetFillMode() == FILL_T::FILLED_WITH_COLOR
  98. || GetFillMode() == FILL_T::FILLED_WITH_BG_BODYCOLOR;
  99. }
  100. bool IsHatchedFill() const
  101. {
  102. return GetFillMode() == FILL_T::HATCH
  103. || GetFillMode() == FILL_T::REVERSE_HATCH
  104. || GetFillMode() == FILL_T::CROSS_HATCH;
  105. }
  106. virtual bool IsFilledForHitTesting() const
  107. {
  108. return IsSolidFill();
  109. }
  110. virtual void SetFilled( bool aFlag )
  111. {
  112. setFilled( aFlag );
  113. }
  114. void SetFillMode( FILL_T aFill );
  115. FILL_T GetFillMode() const { return m_fill; }
  116. void SetFillModeProp( UI_FILL_MODE );
  117. UI_FILL_MODE GetFillModeProp() const;
  118. void SetHatchingDirty() { m_hatchingDirty = true; }
  119. const SHAPE_POLY_SET& GetHatching() const { return m_hatching; }
  120. bool IsClosed() const;
  121. COLOR4D GetFillColor() const { return m_fillColor; }
  122. void SetFillColor( const COLOR4D& aColor ) { m_fillColor = aColor; }
  123. void SetWidth( int aWidth );
  124. virtual int GetWidth() const { return m_stroke.GetWidth(); }
  125. virtual int GetEffectiveWidth() const { return GetWidth(); }
  126. virtual int GetHatchLineWidth() const { return GetEffectiveWidth(); }
  127. virtual int GetHatchLineSpacing() const { return GetHatchLineWidth() * 10; }
  128. void SetLineStyle( const LINE_STYLE aStyle );
  129. LINE_STYLE GetLineStyle() const;
  130. void SetLineColor( const COLOR4D& aColor ) { m_stroke.SetColor( aColor ); }
  131. COLOR4D GetLineColor() const { return m_stroke.GetColor(); }
  132. void SetShape( SHAPE_T aShape ) { m_shape = aShape; }
  133. SHAPE_T GetShape() const { return m_shape; }
  134. /**
  135. * Return the starting point of the graphic.
  136. */
  137. const VECTOR2I& GetStart() const { return m_start; }
  138. int GetStartY() const { return m_start.y; }
  139. int GetStartX() const { return m_start.x; }
  140. void SetStart( const VECTOR2I& aStart )
  141. {
  142. m_start = aStart;
  143. m_endsSwapped = false;
  144. m_hatchingDirty = true;
  145. }
  146. void SetStartY( int y )
  147. {
  148. m_start.y = y;
  149. m_endsSwapped = false;
  150. m_hatchingDirty = true;
  151. }
  152. void SetStartX( int x )
  153. {
  154. m_start.x = x;
  155. m_endsSwapped = false;
  156. m_hatchingDirty = true;
  157. }
  158. void SetCenterY( int y )
  159. {
  160. m_end.y += y - m_start.y;
  161. m_start.y = y;
  162. m_hatchingDirty = true;
  163. }
  164. void SetCenterX( int x )
  165. {
  166. m_end.x += x - m_start.x;
  167. m_start.x = x;
  168. m_hatchingDirty = true;
  169. }
  170. /**
  171. * Return the ending point of the graphic.
  172. */
  173. const VECTOR2I& GetEnd() const { return m_end; }
  174. int GetEndY() const { return m_end.y; }
  175. int GetEndX() const { return m_end.x; }
  176. void SetEnd( const VECTOR2I& aEnd )
  177. {
  178. m_end = aEnd;
  179. m_endsSwapped = false;
  180. m_hatchingDirty = true;
  181. }
  182. void SetEndY( int aY )
  183. {
  184. m_end.y = aY;
  185. m_endsSwapped = false;
  186. m_hatchingDirty = true;
  187. }
  188. void SetEndX( int aX )
  189. {
  190. m_end.x = aX;
  191. m_endsSwapped = false;
  192. m_hatchingDirty = true;
  193. }
  194. void SetRadius( int aX )
  195. {
  196. m_end = m_start + VECTOR2I( aX, 0 );
  197. m_hatchingDirty = true;
  198. }
  199. virtual VECTOR2I GetTopLeft() const { return GetStart(); }
  200. virtual VECTOR2I GetBotRight() const { return GetEnd(); }
  201. virtual void SetTop( int val ) { SetStartY( val ); }
  202. virtual void SetLeft( int val ) { SetStartX( val ); }
  203. virtual void SetRight( int val ) { SetEndX( val ); }
  204. virtual void SetBottom( int val ) { SetEndY( val ); }
  205. void SetBezierC1( const VECTOR2I& aPt ) { m_bezierC1 = aPt; }
  206. const VECTOR2I& GetBezierC1() const { return m_bezierC1; }
  207. void SetBezierC2( const VECTOR2I& aPt ) { m_bezierC2 = aPt; }
  208. const VECTOR2I& GetBezierC2() const { return m_bezierC2; }
  209. VECTOR2I getCenter() const;
  210. void SetCenter( const VECTOR2I& aCenter );
  211. /**
  212. * Set the end point from the angle center and start.
  213. *
  214. * aAngle is:
  215. * - clockwise in right-down coordinate system
  216. * - counter-clockwise in right-up (libedit) coordinate system.
  217. */
  218. void SetArcAngleAndEnd( const EDA_ANGLE& aAngle, bool aCheckNegativeAngle = false );
  219. EDA_ANGLE GetArcAngle() const;
  220. EDA_ANGLE GetSegmentAngle() const;
  221. /**
  222. * Have the start and end points been swapped since they were set?
  223. *
  224. * @return true if they have.
  225. */
  226. bool EndsSwapped() const { return m_endsSwapped; }
  227. // Some attributes are read only, since they are derived from m_Start, m_End, and m_Angle.
  228. // No Set...() function for these attributes.
  229. VECTOR2I GetArcMid() const;
  230. std::vector<VECTOR2I> GetRectCorners() const;
  231. std::vector<VECTOR2I> GetCornersInSequence( EDA_ANGLE angle ) const;
  232. /**
  233. * Calc arc start and end angles such that aStartAngle < aEndAngle. Each may be between
  234. * -360.0 and 360.0.
  235. */
  236. void CalcArcAngles( EDA_ANGLE& aStartAngle, EDA_ANGLE& aEndAngle ) const;
  237. int GetRadius() const;
  238. /**
  239. * Set the three controlling points for an arc.
  240. *
  241. * NB: these are NOT what's currently stored, so we have to do some calculations behind
  242. * the scenes. However, they are what SHOULD be stored.
  243. */
  244. void SetArcGeometry( const VECTOR2I& aStart, const VECTOR2I& aMid, const VECTOR2I& aEnd );
  245. /**
  246. * Set the data used for mid point caching.
  247. *
  248. * If the controlling points remain constant, then we keep the midpoint the same as it was
  249. * when read in. This minimizes VCS churn.
  250. *
  251. * @param aStart Cached start point.
  252. * @param aMid Cached mid point.
  253. * @param aEnd Cached end point.
  254. * @param aCenter Calculated center point using the preceeding three.
  255. */
  256. void SetCachedArcData( const VECTOR2I& aStart, const VECTOR2I& aMid, const VECTOR2I& aEnd,
  257. const VECTOR2I& aCenter );
  258. const std::vector<VECTOR2I>& GetBezierPoints() const { return m_bezierPoints; }
  259. /**
  260. * Duplicate the list of corners in a std::vector<VECTOR2I>.
  261. *
  262. * It must be used only to convert the SHAPE_POLY_SET internal corner buffer
  263. * to a list of VECTOR2Is, and nothing else, because it duplicates the buffer,
  264. * that is inefficient to know for instance the corner count.
  265. */
  266. void DupPolyPointsList( std::vector<VECTOR2I>& aBuffer ) const;
  267. /**
  268. * @return the number of corners of the polygonal shape.
  269. */
  270. int GetPointCount() const;
  271. // Accessors to the polygonal shape
  272. SHAPE_POLY_SET& GetPolyShape() { return m_poly; }
  273. const SHAPE_POLY_SET& GetPolyShape() const { return m_poly; }
  274. /**
  275. * @return true if the polygonal shape is valid (has more than 2 points).
  276. */
  277. bool IsPolyShapeValid() const;
  278. void SetPolyShape( const SHAPE_POLY_SET& aShape )
  279. {
  280. m_poly = aShape;
  281. for( int ii = 0; ii < m_poly.OutlineCount(); ++ii )
  282. {
  283. if( m_poly.HoleCount( ii ) )
  284. {
  285. m_poly.Fracture();
  286. break;
  287. }
  288. }
  289. }
  290. void SetPolyPoints( const std::vector<VECTOR2I>& aPoints );
  291. /**
  292. * Rebuild the m_bezierPoints vertex list that approximate the Bezier curve by a list of
  293. * segments.
  294. *
  295. * Has meaning only for #BEZIER shape.
  296. *
  297. * @param aMinSegLen is the max deviation between the polyline and the curve.
  298. */
  299. void RebuildBezierToSegmentsPointsList( int aMaxError );
  300. /**
  301. * Make a set of SHAPE objects representing the #EDA_SHAPE.
  302. *
  303. * Caller owns the objects.
  304. *
  305. * @param aEdgeOnly indicates only edges should be generated (even if 0 width), and no fill
  306. * shapes.
  307. */
  308. virtual std::vector<SHAPE*> MakeEffectiveShapes( bool aEdgeOnly = false ) const
  309. {
  310. return makeEffectiveShapes( aEdgeOnly );
  311. }
  312. void ShapeGetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList );
  313. void SetLength( const double& aLength );
  314. void SetRectangleHeight( const int& aHeight );
  315. void SetRectangleWidth( const int& aWidth );
  316. void SetRectangle( const long long int& aHeight, const long long int& aWidth );
  317. void SetSegmentAngle( const EDA_ANGLE& aAngle );
  318. bool IsClockwiseArc() const;
  319. /**
  320. * @return the length of the segment using the hypotenuse calculation.
  321. */
  322. double GetLength() const;
  323. int GetRectangleHeight() const;
  324. int GetRectangleWidth() const;
  325. virtual void UpdateHatching() const;
  326. /**
  327. * Convert the shape to a closed polygon.
  328. *
  329. * Circles and arcs are approximated by segments.
  330. *
  331. * @param aBuffer is a buffer to store the polygon.
  332. * @param aClearance is the clearance around the pad.
  333. * @param aError is the maximum deviation from a true arc.
  334. * @param aErrorLoc whether any approximation error should be placed inside or outside
  335. * @param ignoreLineWidth is used for edge cut items where the line width is only for
  336. * visualization
  337. */
  338. void TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, int aClearance, int aError,
  339. ERROR_LOC aErrorLoc, bool ignoreLineWidth = false,
  340. bool includeFill = false ) const;
  341. int Compare( const EDA_SHAPE* aOther ) const;
  342. double Similarity( const EDA_SHAPE& aOther ) const;
  343. bool operator==( const EDA_SHAPE& aOther ) const;
  344. protected:
  345. wxString getFriendlyName() const;
  346. void setPosition( const VECTOR2I& aPos );
  347. VECTOR2I getPosition() const;
  348. virtual void setFilled( bool aFlag )
  349. {
  350. m_fill = aFlag ? FILL_T::FILLED_SHAPE : FILL_T::NO_FILL;
  351. }
  352. void move( const VECTOR2I& aMoveVector );
  353. void rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle );
  354. void flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection );
  355. void scale( double aScale );
  356. virtual EDA_ANGLE getDrawRotation() const { return ANGLE_0; }
  357. const BOX2I getBoundingBox() const;
  358. void computeArcBBox( BOX2I& aBBox ) const;
  359. bool hitTest( const VECTOR2I& aPosition, int aAccuracy = 0 ) const;
  360. bool hitTest( const BOX2I& aRect, bool aContained, int aAccuracy = 0 ) const;
  361. bool hitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const;
  362. const std::vector<VECTOR2I> buildBezierToSegmentsPointsList( int aMaxError ) const;
  363. void beginEdit( const VECTOR2I& aStartPoint );
  364. bool continueEdit( const VECTOR2I& aPosition );
  365. void calcEdit( const VECTOR2I& aPosition );
  366. /**
  367. * Finish editing the shape.
  368. *
  369. * @param aClosed Should polygon shapes be closed (yes for pcbnew/fpeditor, no for libedit).
  370. */
  371. void endEdit( bool aClosed = true );
  372. void setEditState( int aState ) { m_editState = aState; }
  373. virtual bool isMoving() const { return false; }
  374. /**
  375. * Make a set of #SHAPE objects representing the #EDA_SHAPE.
  376. *
  377. * Caller owns the objects.
  378. *
  379. * @param aEdgeOnly indicates only edges should be generated (even if 0 width), and no fill
  380. * shapes.
  381. * @param aLineChainOnly indicates #SHAPE_POLY_SET is being abused slightly to represent a
  382. * lineChain rather than a closed polygon.
  383. */
  384. // fixme: move to shape_compound
  385. std::vector<SHAPE*> makeEffectiveShapes( bool aEdgeOnly, bool aLineChainOnly = false ) const;
  386. virtual int getMaxError() const { return 100; }
  387. protected:
  388. bool m_endsSwapped; // true if start/end were swapped e.g. SetArcAngleAndEnd
  389. SHAPE_T m_shape; // Shape: line, Circle, Arc
  390. STROKE_PARAMS m_stroke; // Line style, width, etc.
  391. FILL_T m_fill;
  392. COLOR4D m_fillColor;
  393. mutable SHAPE_POLY_SET m_hatching;
  394. mutable bool m_hatchingDirty;
  395. long long int m_rectangleHeight;
  396. long long int m_rectangleWidth;
  397. double m_segmentLength;
  398. EDA_ANGLE m_segmentAngle;
  399. VECTOR2I m_start; // Line start point or Circle center
  400. VECTOR2I m_end; // Line end point or Circle 3 o'clock point
  401. VECTOR2I m_arcCenter; // Used only for Arcs: arc end point
  402. ARC_MID m_arcMidData; // Used to store originating data
  403. VECTOR2I m_bezierC1; // Bezier Control Point 1
  404. VECTOR2I m_bezierC2; // Bezier Control Point 2
  405. std::vector<VECTOR2I> m_bezierPoints;
  406. SHAPE_POLY_SET m_poly; // Stores the S_POLYGON shape
  407. int m_editState;
  408. bool m_proxyItem; // A shape storing proxy information (ie: a pad
  409. // number box, thermal spoke template, etc.)
  410. };
  411. #ifndef SWIG
  412. DECLARE_ENUM_TO_WXANY( SHAPE_T );
  413. DECLARE_ENUM_TO_WXANY( LINE_STYLE );
  414. DECLARE_ENUM_TO_WXANY( UI_FILL_MODE );
  415. #endif