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) 2004-2021 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 
25 #ifndef SCH_ITEM_H
26 #define SCH_ITEM_H
27 
28 #include <unordered_map>
29 #include <unordered_set>
30 
31 #include <eda_item.h>
32 #include <plotters/plotter.h>      // for PLOT_DASH_TYPE definition
33 
34 #include <default_values.h>
35 #include <sch_sheet_path.h>
36 #include <netclass.h>
37 
38 class CONNECTION_GRAPH;
39 class SCH_CONNECTION;
40 class SCH_SHEET_PATH;
41 class SCHEMATIC;
42 class LINE_READER;
43 class SCH_EDIT_FRAME;
44 class wxFindReplaceData;
45 class PLOTTER;
46 class NETLIST_OBJECT;
47 class NETLIST_OBJECT_LIST;
48 
49 using KIGFX::RENDER_SETTINGS;
50 
51 
52 enum FIELDS_AUTOPLACED
53 {
54     FIELDS_AUTOPLACED_NO = 0,
55     FIELDS_AUTOPLACED_AUTO,
56     FIELDS_AUTOPLACED_MANUAL
57 };
58 
59 
60 enum DANGLING_END_T
61 {
62     UNKNOWN = 0,
63     WIRE_END,
64     BUS_END,
65     JUNCTION_END,
66     PIN_END,
67     LABEL_END,
68     BUS_ENTRY_END,
69     WIRE_ENTRY_END,
70     SHEET_LABEL_END,
71     NO_CONNECT_END,
72 };
73 
74 
75 /**
76  * Helper class used to store the state of schematic items that can be connected to
77  * other schematic items.
78  */
79 class DANGLING_END_ITEM
80 {
81 public:
DANGLING_END_ITEM(DANGLING_END_T aType,EDA_ITEM * aItem,const wxPoint & aPosition)82     DANGLING_END_ITEM( DANGLING_END_T aType, EDA_ITEM* aItem, const wxPoint& aPosition )
83     {
84         m_item = aItem;
85         m_type = aType;
86         m_pos = aPosition;
87         m_parent = aItem;
88     }
89 
DANGLING_END_ITEM(DANGLING_END_T aType,EDA_ITEM * aItem,const wxPoint & aPosition,const EDA_ITEM * aParent)90     DANGLING_END_ITEM( DANGLING_END_T aType, EDA_ITEM* aItem, const wxPoint& aPosition,
91                        const EDA_ITEM* aParent )
92     {
93         m_item = aItem;
94         m_type = aType;
95         m_pos = aPosition;
96         m_parent = aParent;
97     }
98 
99     bool operator==( const DANGLING_END_ITEM& aB ) const
100     {
101         return GetItem() == aB.GetItem()
102             && GetPosition() == aB.GetPosition()
103             && GetType() == aB.GetType()
104             && GetParent() == aB.GetParent();
105     }
106 
107     bool operator!=( const DANGLING_END_ITEM& aB ) const
108     {
109         return GetItem() != aB.GetItem()
110                 || GetPosition() != aB.GetPosition()
111                 || GetType() != aB.GetType()
112                 || GetParent() != aB.GetParent();;
113     }
114 
115     bool operator<( const DANGLING_END_ITEM& rhs ) const
116     {
117         return( m_pos.x < rhs.m_pos.x || ( m_pos.x == rhs.m_pos.x && m_pos.y < rhs.m_pos.y )
118                 || ( m_pos == rhs.m_pos && m_item < rhs.m_item ) );
119     }
120 
GetPosition()121     wxPoint GetPosition() const { return m_pos; }
GetItem()122     EDA_ITEM* GetItem() const { return m_item; }
GetParent()123     const EDA_ITEM* GetParent() const { return m_parent; }
GetType()124     DANGLING_END_T GetType() const { return m_type; }
125 
126 private:
127     EDA_ITEM*       m_item;         /// A pointer to the connectable object.
128     wxPoint         m_pos;          /// The position of the connection point.
129     DANGLING_END_T  m_type;         /// The type of connection of #m_item.
130     const EDA_ITEM* m_parent;       /// A pointer to the parent object (in the case of pins)
131 };
132 
133 
134 typedef std::unordered_set<SCH_ITEM*> SCH_ITEM_SET;
135 
136 
137 /**
138  * Simple container to manage line stroke parameters.
139  */
140 class STROKE_PARAMS
141 {
142 public:
143     STROKE_PARAMS( int aWidth = Mils2iu( DEFAULT_LINE_WIDTH_MILS ),
144                    PLOT_DASH_TYPE aPlotStyle = PLOT_DASH_TYPE::DEFAULT,
145                    const COLOR4D& aColor = COLOR4D::UNSPECIFIED ) :
m_width(aWidth)146             m_width( aWidth ),
147             m_plotstyle( aPlotStyle ),
148             m_color( aColor )
149     {
150     }
151 
GetWidth()152     int GetWidth() const { return m_width; }
SetWidth(int aWidth)153     void SetWidth( int aWidth ) { m_width = aWidth; }
154 
GetPlotStyle()155     PLOT_DASH_TYPE GetPlotStyle() const { return m_plotstyle; }
SetPlotStyle(PLOT_DASH_TYPE aPlotStyle)156     void SetPlotStyle( PLOT_DASH_TYPE aPlotStyle ) { m_plotstyle = aPlotStyle; }
157 
GetColor()158     COLOR4D GetColor() const { return m_color; }
SetColor(const COLOR4D & aColor)159     void SetColor( const COLOR4D& aColor ) { m_color = aColor; }
160 
161     bool operator!=( const STROKE_PARAMS& aOther )
162     {
163         return m_width != aOther.m_width
164                 || m_plotstyle != aOther.m_plotstyle
165                 || m_color != aOther.m_color;
166     }
167 
168 private:
169     int            m_width;
170     PLOT_DASH_TYPE m_plotstyle;
171     COLOR4D        m_color;
172 };
173 
174 
175 /**
176  * Base class for any item which can be embedded within the #SCHEMATIC container class,
177  * and therefore instances of derived classes should only be found in EESCHEMA or other
178  * programs that use class SCHEMATIC and its contents.
179  *
180  * The corresponding class in Pcbnew is #BOARD_ITEM.
181  */
182 class SCH_ITEM : public EDA_ITEM
183 {
184 public:
185     SCH_ITEM( EDA_ITEM* aParent, KICAD_T aType );
186 
187     SCH_ITEM( const SCH_ITEM& aItem );
188 
189     SCH_ITEM& operator=( const SCH_ITEM& aPin );
190 
191     virtual ~SCH_ITEM();
192 
GetClass()193     virtual wxString GetClass() const override
194     {
195         return wxT( "SCH_ITEM" );
196     }
197 
198     /**
199      * Swap the internal data structures \a aItem with the schematic item.
200      * Obviously, aItem must have the same type than me.
201      * @param aItem The item to swap the data structures with.
202      */
203     virtual void SwapData( SCH_ITEM* aItem );
204 
205     /**
206      * Routine to create a new copy of given item.
207      * The new object is not put in draw list (not linked).
208      *
209      * @param doClone (default = false) indicates unique values (such as timestamp and
210      *                sheet name) should be duplicated.  Use only for undo/redo operations.
211      */
212     SCH_ITEM* Duplicate( bool doClone = false ) const;
213 
214     /**
215      * @return true for items which are moved with the anchor point at mouse cursor
216      *  and false for items moved with no reference to anchor
217      * Usually return true for small items (labels, junctions) and false for
218      * items which can be large (hierarchical sheets, symbols)
219      */
IsMovableFromAnchorPoint()220     virtual bool IsMovableFromAnchorPoint() const { return true; }
221 
GetStoredPos()222     wxPoint& GetStoredPos() { return m_storedPos; }
SetStoredPos(const wxPoint & aPos)223     void     SetStoredPos( const wxPoint& aPos ) { m_storedPos = aPos; }
224 
225     /**
226      * Searches the item hierarchy to find a SCHEMATIC.
227      *
228      * Every SCH_ITEM that lives on a SCH_SCREEN should be parented to either that screen
229      * or another SCH_ITEM on the same screen (for example, pins to their symbols).
230      *
231      * Every SCH_SCREEN should be parented to the SCHEMATIC.
232      *
233      * @note This hierarchy is not the same as the sheet hierarchy!
234      *
235      * @return the parent schematic this item lives on, or nullptr.
236      */
237     SCHEMATIC* Schematic() const;
238 
239     /**
240      * @return true if the object is locked, else false.
241      */
IsLocked()242     virtual bool IsLocked() const { return false; }
243 
244     /**
245      * Set the 'lock' status to \a aLocked for of this item.
246      */
SetLocked(bool aLocked)247     virtual void SetLocked( bool aLocked ) {}
248 
249     /**
250      * Allow items to support hypertext actions when hovered/clicked.
251      */
IsHypertext()252     virtual bool IsHypertext() const { return false; }
253 
DoHypertextMenu(EDA_DRAW_FRAME * aFrame)254     virtual void DoHypertextMenu( EDA_DRAW_FRAME* aFrame ) { }
255 
256     /**
257      * Return the layer this item is on.
258      */
GetLayer()259     SCH_LAYER_ID GetLayer() const { return m_layer; }
260 
261     /**
262      * Set the layer this item is on.
263      *
264      * @param aLayer The layer number.
265      */
SetLayer(SCH_LAYER_ID aLayer)266     void SetLayer( SCH_LAYER_ID aLayer ) { m_layer = aLayer; }
267 
268     /**
269      * Return the layers the item is drawn on (which may be more than its "home" layer)
270      */
271     void ViewGetLayers( int aLayers[], int& aCount ) const override;
272 
273     /**
274      * @return the size of the "pen" that be used to draw or plot this item
275      */
GetPenWidth()276     virtual int GetPenWidth() const { return 0; }
277 
278     /**
279      * Print a schematic item.
280      *
281      * Each schematic item should have its own method
282      *
283      * @param aOffset is the drawing offset (usually {0,0} but can be different when moving an
284      *                object).
285      */
286     virtual void Print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset ) = 0;
287 
288     /**
289      * Move the item by \a aMoveVector to a new position.
290      */
291     virtual void Move( const wxPoint& aMoveVector ) = 0;
292 
293     /**
294      * Mirror item horizontally about \a aCenter.
295      */
296     virtual void MirrorHorizontally( int aCenter ) = 0;
297 
298     /**
299      * Mirror item vertically about \a aCenter.
300      */
301     virtual void MirrorVertically( int aCenter ) = 0;
302 
303     /**
304      * Rotate the item around \a aCenter 90 degrees in the clockwise direction.
305      */
306     virtual void Rotate( const wxPoint& aCenter ) = 0;
307 
308     /**
309      * Add the schematic item end points to \a aItemList if the item has end points.
310      *
311      * The default version doesn't do anything since many of the schematic object cannot
312      * be tested for dangling ends.  If you add a new schematic item that can have a
313      * dangling end ( no connect ), override this method to provide the correct end
314      * points.
315      *
316      * @param aItemList is the list of DANGLING_END_ITEMS to add to.
317      */
GetEndPoints(std::vector<DANGLING_END_ITEM> & aItemList)318     virtual void GetEndPoints( std::vector< DANGLING_END_ITEM >& aItemList ) {}
319 
320     /**
321      * Test the schematic item to \a aItemList to check if it's dangling state has changed.
322      *
323      * Note that the return value only true when the state of the test has changed.  Use
324      * the IsDangling() method to get the current dangling state of the item.  Some of
325      * the schematic objects cannot be tested for a dangling state, the default method
326      * always returns false.  Only override the method if the item can be tested for a
327      * dangling state.
328      *
329      * If aSheet is passed a non-null pointer to a SCH_SHEET_PATH, the overridden method can
330      * optionally use it to update sheet-local connectivity information
331      *
332      * @param aItemList is the list of items to test item against.
333      * @param aSheet is the sheet path to update connections for.
334      * @return True if the dangling state has changed from it's current setting.
335      */
336     virtual bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
337                                       const SCH_SHEET_PATH* aPath = nullptr )
338     {
339         return false;
340     }
341 
IsDangling()342     virtual bool IsDangling() const { return false; }
343 
CanConnect(const SCH_ITEM * aItem)344     virtual bool CanConnect( const SCH_ITEM* aItem ) const { return m_layer == aItem->GetLayer(); }
345 
346     /**
347      * @return true if the schematic item can connect to another schematic item.
348      */
IsConnectable()349     virtual bool IsConnectable() const { return false; }
350 
351     /**
352      * @return true if the given point can start drawing (usually means the anchor is
353      *         unused/free/dangling).
354      */
IsPointClickableAnchor(const wxPoint & aPos)355     virtual bool IsPointClickableAnchor( const wxPoint& aPos ) const { return false; }
356 
357     /**
358      * Add all the connection points for this item to \a aPoints.
359      *
360      * Not all schematic items have connection points so the default method does nothing.
361      *
362      * @param aPoints is the list of connection points to add to.
363      */
GetConnectionPoints()364     virtual std::vector<wxPoint> GetConnectionPoints() const { return {}; }
365 
366     /**
367      * Clears all of the connection items from the list.
368      *
369      * The vector release method is used to prevent the item pointers from being deleted.
370      * Do not use the vector erase method on the connection list.
371      */
ClearConnections()372     void ClearConnections() { m_connections.clear(); }
373 
374     /**
375      * Test the item to see if it is connected to \a aPoint.
376      *
377      * @param aPoint is a reference to a wxPoint object containing the coordinates to test.
378      * @return True if connection to \a aPoint exists.
379      */
380     bool IsConnected( const wxPoint& aPoint ) const;
381 
382     /**
383      * Retrieve the connection associated with this object in the given sheet.
384      *
385      * @note The returned value can be nullptr.
386      */
387     SCH_CONNECTION* Connection( const SCH_SHEET_PATH* aSheet = nullptr ) const;
388 
389     /**
390      * Retrieve the set of items connected to this item on the given sheet.
391      */
392     SCH_ITEM_SET& ConnectedItems( const SCH_SHEET_PATH& aPath );
393 
394     /**
395      * Add a connection link between this item and another.
396      */
397     void AddConnectionTo( const SCH_SHEET_PATH& aPath, SCH_ITEM* aItem );
398 
399     /**
400      * Create a new connection object associated with this object.
401      *
402      * @param aPath is the sheet path to initialize.
403      */
404     SCH_CONNECTION* InitializeConnection( const SCH_SHEET_PATH& aPath, CONNECTION_GRAPH* aGraph );
405 
406     SCH_CONNECTION* GetOrInitConnection( const SCH_SHEET_PATH& aPath, CONNECTION_GRAPH* aGraph );
407 
408     /**
409      * Return true if this item should propagate connection info to \a aItem.
410      */
ConnectionPropagatesTo(const EDA_ITEM * aItem)411     virtual bool ConnectionPropagatesTo( const EDA_ITEM* aItem ) const { return true; }
412 
IsConnectivityDirty()413     bool IsConnectivityDirty() const { return m_connectivity_dirty; }
414 
415     void SetConnectivityDirty( bool aDirty = true ) { m_connectivity_dirty = aDirty; }
416 
SetLastResolvedState(const SCH_ITEM * aItem)417     virtual void SetLastResolvedState( const SCH_ITEM* aItem ) { }
418 
419     NETCLASSPTR NetClass( const SCH_SHEET_PATH* aSheet = nullptr ) const;
420 
421     /**
422      * Return whether the fields have been automatically placed.
423      */
GetFieldsAutoplaced()424     FIELDS_AUTOPLACED GetFieldsAutoplaced() const { return m_fieldsAutoplaced; }
425 
SetFieldsAutoplaced()426     void SetFieldsAutoplaced() { m_fieldsAutoplaced = FIELDS_AUTOPLACED_AUTO; }
ClearFieldsAutoplaced()427     void ClearFieldsAutoplaced() { m_fieldsAutoplaced = FIELDS_AUTOPLACED_NO; }
428 
429     /**
430      * Autoplace fields only if correct to do so automatically.
431      *
432      * Fields that have been moved by hand are not automatically placed.
433      *
434      * @param aScreen is the SCH_SCREEN associated with the current instance of the symbol.
435      */
AutoAutoplaceFields(SCH_SCREEN * aScreen)436     void AutoAutoplaceFields( SCH_SCREEN* aScreen )
437     {
438         if( GetFieldsAutoplaced() )
439             AutoplaceFields( aScreen, GetFieldsAutoplaced() == FIELDS_AUTOPLACED_MANUAL );
440     }
441 
AutoplaceFields(SCH_SCREEN * aScreen,bool aManual)442     virtual void AutoplaceFields( SCH_SCREEN* aScreen, bool aManual ) { }
443 
RunOnChildren(const std::function<void (SCH_ITEM *)> & aFunction)444     virtual void RunOnChildren( const std::function<void( SCH_ITEM* )>& aFunction ) { }
445 
446     /**
447      * Check if this schematic item has line stoke properties.
448      *
449      * @see #STROKE_PARAMS
450      *
451      * @return true if this schematic item support line stroke properties.  Otherwise, false.
452      */
HasLineStroke()453     virtual bool HasLineStroke() const { return false; }
454 
GetStroke()455     virtual STROKE_PARAMS GetStroke() const { wxCHECK( false, STROKE_PARAMS() ); }
456 
SetStroke(const STROKE_PARAMS & aStroke)457     virtual void SetStroke( const STROKE_PARAMS& aStroke ) { wxCHECK( false, /* void */ ); }
458 
459     /**
460      * Plot the schematic item to \a aPlotter.
461      *
462      * @param aPlotter is the #PLOTTER object to plot to.
463      */
464     virtual void Plot( PLOTTER* aPlotter ) const;
465 
466     virtual bool operator <( const SCH_ITEM& aItem ) const;
467 
468 private:
469     friend class CONNECTION_GRAPH;
470 
471     /**
472      * Provide the object specific test to see if it is connected to \a aPosition.
473      *
474      * @note Override this function if the derived object can be connect to another
475      *       object such as a wire, bus, or junction.  Do not override this function
476      *       for objects that cannot have connections.  The default will always return
477      *       false.  This functions is call through the public function IsConnected()
478      *       which performs tests common to all schematic items before calling the
479      *       item specific connection testing.
480      *
481      * @param aPosition is a reference to a wxPoint object containing the test position.
482      * @return True if connection to \a aPosition exists.
483      */
doIsConnected(const wxPoint & aPosition)484     virtual bool doIsConnected( const wxPoint& aPosition ) const { return false; }
485 
486 protected:
487     SCH_LAYER_ID      m_layer;
488     EDA_ITEMS         m_connections;      // List of items connected to this item.
489     FIELDS_AUTOPLACED m_fieldsAutoplaced; // indicates status of field autoplacement
490     wxPoint           m_storedPos;        // a temporary variable used in some move commands
491                                           // to store a initial pos of the item or mouse cursor
492 
493     /// Store pointers to other items that are connected to this one, per sheet.
494     std::unordered_map<SCH_SHEET_PATH, SCH_ITEM_SET> m_connected_items;
495 
496     /// Store connectivity information, per sheet.
497     std::unordered_map<SCH_SHEET_PATH, SCH_CONNECTION*> m_connection_map;
498 
499     bool              m_connectivity_dirty;
500 };
501 
502 #endif /* SCH_ITEM_H */
503