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.

528 lines
14 KiB

  1. /*
  2. * This program source code file is part of KICAD, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2014-2017 CERN
  5. * Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * @author Maciej Suminski <maciej.suminski@cern.ch>
  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. #ifndef EDIT_POINTS_H_
  27. #define EDIT_POINTS_H_
  28. #include <eda_item.h>
  29. #include <layers_id_colors_and_visibility.h>
  30. #include <list>
  31. #include <deque>
  32. #include <memory>
  33. #include "edit_constraints.h"
  34. #include <view/view.h>
  35. /**
  36. * Represent a single point that can be used for modifying items.
  37. *
  38. * It is directly related to one of points in a graphical item (e.g. vertex of a zone or
  39. * center of a circle).
  40. */
  41. class EDIT_POINT
  42. {
  43. public:
  44. /**
  45. * @param aPoint stores coordinates for EDIT_POINT.
  46. */
  47. EDIT_POINT( const VECTOR2I& aPoint, std::pair<EDA_ITEM*, int> aConnected = { nullptr, 0 } ) :
  48. m_position( aPoint ),
  49. m_isActive( false ),
  50. m_isHover( false ),
  51. m_gridConstraint( SNAP_TO_GRID ),
  52. m_connected( aConnected )
  53. {
  54. }
  55. virtual ~EDIT_POINT() {}
  56. /**
  57. * Return coordinates of an EDIT_POINT.
  58. *
  59. * @note It may be different than coordinates of a graphical item that is bound to the
  60. * EDIT_POINT.
  61. */
  62. virtual VECTOR2I GetPosition() const
  63. {
  64. return m_position;
  65. }
  66. /**
  67. * Return a connected item record comprising an EDA_ITEM* and a STARTPOINT/ENDPOINT flag.
  68. */
  69. virtual std::pair<EDA_ITEM*, int> GetConnected() const
  70. {
  71. return m_connected;
  72. }
  73. /**
  74. * Return X coordinate of an EDIT_POINT.
  75. */
  76. inline int GetX() const
  77. {
  78. return GetPosition().x;
  79. }
  80. /**
  81. * Return Y coordinate of an EDIT_POINT.
  82. */
  83. inline int GetY() const
  84. {
  85. return GetPosition().y;
  86. }
  87. /**
  88. * Set new coordinates for an EDIT_POINT.
  89. *
  90. * It does not change the coordinates of a graphical item.
  91. *
  92. * @param aPosition are new coordinates.
  93. */
  94. virtual void SetPosition( const VECTOR2I& aPosition )
  95. {
  96. m_position = aPosition;
  97. }
  98. virtual void SetPosition( int x, int y )
  99. {
  100. m_position.x = x;
  101. m_position.y = y;
  102. }
  103. /**
  104. * Check if given point is within a square centered in the EDIT_POINT position.
  105. *
  106. * @param aPoint is point to be checked.
  107. * @param aSize is length of the square side.
  108. */
  109. bool WithinPoint( const VECTOR2I& aPoint, unsigned int aSize ) const;
  110. /**
  111. * Set a constraint for and EDIT_POINT.
  112. *
  113. * @param aConstraint is the constraint to be set.
  114. */
  115. void SetConstraint( EDIT_CONSTRAINT<EDIT_POINT>* aConstraint )
  116. {
  117. m_constraint.reset( aConstraint );
  118. }
  119. /**
  120. * Return the constraint imposed on an EDIT_POINT. If there are no constraints, NULL is
  121. * returned.
  122. */
  123. EDIT_CONSTRAINT<EDIT_POINT>* GetConstraint() const
  124. {
  125. return m_constraint.get();
  126. }
  127. /**
  128. * Remove previously set constraint.
  129. */
  130. inline void ClearConstraint()
  131. {
  132. m_constraint.reset();
  133. }
  134. /**
  135. * Check if point is constrained.
  136. *
  137. * @return True is point is constrained, false otherwise.
  138. */
  139. inline bool IsConstrained() const
  140. {
  141. return m_constraint != NULL;
  142. }
  143. /**
  144. * Correct coordinates of an EDIT_POINT by applying previously set constraint.
  145. */
  146. virtual void ApplyConstraint()
  147. {
  148. if( m_constraint )
  149. m_constraint->Apply();
  150. }
  151. bool IsActive() const { return m_isActive; }
  152. void SetActive( bool aActive = true ) { m_isActive = aActive; }
  153. bool IsHover() const { return m_isHover; }
  154. void SetHover( bool aHover = true ) { m_isHover = aHover; }
  155. GRID_CONSTRAINT_TYPE GetGridConstraint() const { return m_gridConstraint; }
  156. void SetGridConstraint( GRID_CONSTRAINT_TYPE aConstraint ) { m_gridConstraint = aConstraint; }
  157. bool operator==( const EDIT_POINT& aOther ) const
  158. {
  159. return m_position == aOther.m_position;
  160. }
  161. ///< Single point size in pixels
  162. static const int POINT_SIZE = 10;
  163. ///< Border size when not hovering
  164. static const int BORDER_SIZE = 2;
  165. ///< Border size when hovering
  166. static const int HOVER_SIZE = 5;
  167. private:
  168. VECTOR2I m_position; ///< Position of EDIT_POINT.
  169. bool m_isActive; ///< True if this point is being manipulated.
  170. bool m_isHover; ///< True if this point is being hovered over.
  171. GRID_CONSTRAINT_TYPE m_gridConstraint; ///< Describe the grid snapping behavior.
  172. ///< An optional connected item record used to mimic polyLine behavior with individual
  173. ///< line segments.
  174. std::pair<EDA_ITEM*, int> m_connected;
  175. ///< Constraint for the point, NULL if none
  176. std::shared_ptr<EDIT_CONSTRAINT<EDIT_POINT> > m_constraint;
  177. };
  178. /**
  179. * Represent a line connecting two EDIT_POINTs.
  180. *
  181. * This allows one to move them both by dragging the EDIT_POINT in the middle. It uses
  182. * references to EDIT_POINTs, all coordinates are automatically synchronized.
  183. */
  184. class EDIT_LINE : public EDIT_POINT
  185. {
  186. public:
  187. /**
  188. * @param aOrigin is the origin of EDIT_LINE.
  189. * @param aEnd is the end of EDIT_LINE.
  190. */
  191. EDIT_LINE( EDIT_POINT& aOrigin, EDIT_POINT& aEnd ) :
  192. EDIT_POINT( aOrigin.GetPosition() + ( aEnd.GetPosition() - aOrigin.GetPosition() ) / 2 ),
  193. m_origin( aOrigin ),
  194. m_end( aEnd )
  195. {
  196. SetGridConstraint( SNAP_BY_GRID );
  197. }
  198. ///< @copydoc EDIT_POINT::GetPosition()
  199. virtual VECTOR2I GetPosition() const override
  200. {
  201. return ( m_origin.GetPosition() + m_end.GetPosition() ) / 2;
  202. }
  203. ///< @copydoc EDIT_POINT::GetPosition()
  204. virtual void SetPosition( const VECTOR2I& aPosition ) override
  205. {
  206. VECTOR2I difference = aPosition - GetPosition();
  207. m_origin.SetPosition( m_origin.GetPosition() + difference );
  208. m_end.SetPosition( m_end.GetPosition() + difference );
  209. }
  210. ///< @copydoc EDIT_POINT::ApplyConstraint()
  211. virtual void ApplyConstraint() override
  212. {
  213. if( m_constraint )
  214. m_constraint->Apply();
  215. m_origin.ApplyConstraint();
  216. m_end.ApplyConstraint();
  217. }
  218. /**
  219. * Set a constraint for and EDIT_POINT.
  220. *
  221. * @param aConstraint is the constraint to be set.
  222. */
  223. void SetConstraint( EDIT_CONSTRAINT<EDIT_LINE>* aConstraint )
  224. {
  225. m_constraint.reset( aConstraint );
  226. }
  227. /**
  228. * Return the constraint imposed on an EDIT_POINT. If there are no constraints, NULL is
  229. * returned.
  230. */
  231. EDIT_CONSTRAINT<EDIT_LINE>* GetConstraint() const
  232. {
  233. return m_constraint.get();
  234. }
  235. /**
  236. * Return the origin EDIT_POINT.
  237. */
  238. EDIT_POINT& GetOrigin()
  239. {
  240. return m_origin;
  241. }
  242. const EDIT_POINT& GetOrigin() const
  243. {
  244. return m_origin;
  245. }
  246. /**
  247. * Return the end EDIT_POINT.
  248. */
  249. EDIT_POINT& GetEnd()
  250. {
  251. return m_end;
  252. }
  253. const EDIT_POINT& GetEnd() const
  254. {
  255. return m_end;
  256. }
  257. bool operator==( const EDIT_POINT& aOther ) const
  258. {
  259. return GetPosition() == aOther.GetPosition();
  260. }
  261. bool operator==( const EDIT_LINE& aOther ) const
  262. {
  263. return m_origin == aOther.m_origin && m_end == aOther.m_end;
  264. }
  265. private:
  266. EDIT_POINT& m_origin; ///< Origin point for a line
  267. EDIT_POINT& m_end; ///< End point for a line
  268. ///< Constraint for the point, NULL if none
  269. std::shared_ptr<EDIT_CONSTRAINT<EDIT_LINE> > m_constraint;
  270. };
  271. /**
  272. * EDIT_POINTS is a #VIEW_ITEM that manages EDIT_POINTs and EDIT_LINEs and draws them.
  273. */
  274. class EDIT_POINTS : public EDA_ITEM
  275. {
  276. public:
  277. /**
  278. * @param aParent is the item to which EDIT_POINTs are related.
  279. */
  280. EDIT_POINTS( EDA_ITEM* aParent );
  281. /**
  282. * Return a point that is at given coordinates or NULL if there is no such point.
  283. *
  284. * @param aLocation is the location for searched point.
  285. */
  286. EDIT_POINT* FindPoint( const VECTOR2I& aLocation, KIGFX::VIEW *aView );
  287. /**
  288. * Return parent of the EDIT_POINTS.
  289. */
  290. EDA_ITEM* GetParent() const
  291. {
  292. return m_parent;
  293. }
  294. /**
  295. * Add an EDIT_POINT.
  296. *
  297. * @param aPoint is the new point.
  298. */
  299. void AddPoint( const EDIT_POINT& aPoint )
  300. {
  301. m_points.push_back( aPoint );
  302. }
  303. /**
  304. * Add an EDIT_POINT.
  305. *
  306. * @param aPoint are coordinates of the new point.
  307. */
  308. void AddPoint( const VECTOR2I& aPoint, std::pair<EDA_ITEM*, int> aConnected = { nullptr, 0 } )
  309. {
  310. AddPoint( EDIT_POINT( aPoint, aConnected ) );
  311. }
  312. /**
  313. * Adds an EDIT_LINE.
  314. *
  315. * @param aLine is the new line.
  316. */
  317. void AddLine( const EDIT_LINE& aLine )
  318. {
  319. m_lines.push_back( aLine );
  320. }
  321. /**
  322. * Adds an EDIT_LINE.
  323. *
  324. * @param aOrigin is the origin for a new line.
  325. * @param aEnd is the end for a new line.
  326. */
  327. void AddLine( EDIT_POINT& aOrigin, EDIT_POINT& aEnd )
  328. {
  329. m_lines.emplace_back( aOrigin, aEnd );
  330. }
  331. /**
  332. * Adds a break, indicating the end of a contour.
  333. */
  334. void AddBreak()
  335. {
  336. assert( m_points.size() > 0 );
  337. m_contours.push_back( m_points.size() - 1 );
  338. }
  339. /**
  340. * Return index of the contour origin for a point with given index.
  341. *
  342. * @param aPointIdx is the index of point for which the contour origin is searched.
  343. * @return Index of the contour origin point.
  344. */
  345. int GetContourStartIdx( int aPointIdx ) const;
  346. /**
  347. * Return index of the contour finish for a point with given index.
  348. *
  349. * @param aPointIdx is the index of point for which the contour finish is searched.
  350. * @return Index of the contour finish point.
  351. */
  352. int GetContourEndIdx( int aPointIdx ) const;
  353. /**
  354. * Check if a point with given index is a contour origin.
  355. *
  356. * @param aPointIdx is the index of the point to be checked.
  357. * @return True if the point is an origin of a contour.
  358. */
  359. bool IsContourStart( int aPointIdx ) const;
  360. /**
  361. * Check is a point with given index is a contour finish.
  362. *
  363. * @param aPointIdx is the index of the point to be checked.
  364. * @return True if the point is a finish of a contour.
  365. */
  366. bool IsContourEnd( int aPointIdx ) const;
  367. /**
  368. * Return the point that is after the given point in the list.
  369. *
  370. * @param aPoint is the point that is supposed to be preceding the searched point.
  371. * @param aTraverseContours decides if in case of breaks should we return to the origin
  372. * of contour or continue with the next contour.
  373. * @return The point following aPoint in the list. If aPoint is the first in
  374. * the list, the last from the list will be returned. If there are no points at
  375. * all, NULL is returned.
  376. */
  377. EDIT_POINT* Previous( const EDIT_POINT& aPoint, bool aTraverseContours = true );
  378. EDIT_LINE* Previous( const EDIT_LINE& aLine );
  379. /**
  380. * Return the point that is before the given point in the list.
  381. *
  382. * @param aPoint is the point that is supposed to be following the searched point.
  383. * @param aTraverseContours decides if in case of breaks should we return to the origin
  384. * of contour or continue with the next contour.
  385. * @return The point preceding aPoint in the list. If aPoint is the last in the list, the
  386. * first point from the list will be returned. If there are no points at all,
  387. * NULL is returned.
  388. */
  389. EDIT_POINT* Next( const EDIT_POINT& aPoint, bool aTraverseContours = true );
  390. EDIT_LINE* Next( const EDIT_LINE& aLine );
  391. EDIT_POINT& Point( unsigned int aIndex )
  392. {
  393. return m_points[aIndex];
  394. }
  395. const EDIT_POINT& Point( unsigned int aIndex ) const
  396. {
  397. return m_points[aIndex];
  398. }
  399. EDIT_LINE& Line( unsigned int aIndex )
  400. {
  401. return m_lines[aIndex];
  402. }
  403. const EDIT_LINE& Line( unsigned int aIndex ) const
  404. {
  405. return m_lines[aIndex];
  406. }
  407. /**
  408. * Return number of stored EDIT_POINTs.
  409. */
  410. unsigned int PointsSize() const
  411. {
  412. return m_points.size();
  413. }
  414. /**
  415. * Return number of stored EDIT_LINEs.
  416. */
  417. unsigned int LinesSize() const
  418. {
  419. return m_lines.size();
  420. }
  421. ///< @copydoc VIEW_ITEM::ViewBBox()
  422. virtual const BOX2I ViewBBox() const override;
  423. ///< @copydoc VIEW_ITEM::ViewDraw()
  424. virtual void ViewDraw( int aLayer, KIGFX::VIEW* aView ) const override;
  425. ///< @copydoc VIEW_ITEM::ViewGetLayers()
  426. virtual void ViewGetLayers( int aLayers[], int& aCount ) const override
  427. {
  428. aCount = 1;
  429. aLayers[0] = LAYER_GP_OVERLAY ;
  430. }
  431. #if defined(DEBUG)
  432. void Show( int x, std::ostream& st ) const override
  433. {
  434. }
  435. #endif
  436. /**
  437. * Get the class name.
  438. *
  439. * @return string "EDIT_POINTS".
  440. */
  441. virtual wxString GetClass() const override
  442. {
  443. return wxT( "EDIT_POINTS" );
  444. }
  445. private:
  446. EDA_ITEM* m_parent; ///< Parent of the EDIT_POINTs.
  447. std::deque<EDIT_POINT> m_points; ///< EDIT_POINTs for modifying m_parent.
  448. std::deque<EDIT_LINE> m_lines; ///< EDIT_LINEs for modifying m_parent.
  449. std::list<int> m_contours; ///< Indices of end contour points.
  450. bool m_allowPoints; ///< If false, only allow editing of EDIT_LINES.
  451. };
  452. #endif /* EDIT_POINTS_H_ */