KiCad PCB EDA Suite
sch_bus_entry.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2004 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 2004-2019 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 #include <fctsys.h>
26 #include <gr_basic.h>
27 #include <macros.h>
28 #include <sch_draw_panel.h>
29 #include <trigo.h>
30 #include <common.h>
31 #include <richio.h>
32 #include <plotter.h>
33 #include <bitmaps.h>
34 #include <eeschema_config.h>
35 #include <general.h>
36 #include <sch_bus_entry.h>
37 #include <sch_line.h>
38 #include <sch_text.h>
40 
41 
42 SCH_BUS_ENTRY_BASE::SCH_BUS_ENTRY_BASE( KICAD_T aType, const wxPoint& pos, char shape ) :
43  SCH_ITEM( NULL, aType )
44 {
45  m_pos = pos;
46  m_size.x = Mils2iu( 100 );
47  m_size.y = Mils2iu( 100 );
48 
49  if( shape == '/' )
50  m_size.y *= -1;
51 
53 }
54 
55 
58 {
60  m_connected_bus_item = nullptr;
61 }
62 
63 
64 SCH_BUS_BUS_ENTRY::SCH_BUS_BUS_ENTRY( const wxPoint& pos, char shape ) :
66 {
68  m_connected_bus_items[0] = nullptr;
69  m_connected_bus_items[1] = nullptr;
70 }
71 
72 
74 {
75  return new SCH_BUS_WIRE_ENTRY( *this );
76 }
77 
78 
80 {
81  return new SCH_BUS_BUS_ENTRY( *this );
82 }
83 
84 
85 bool SCH_BUS_ENTRY_BASE::doIsConnected( const wxPoint& aPosition ) const
86 {
87  return ( m_pos == aPosition || m_End() == aPosition );
88 }
89 
90 
92 {
93  return wxPoint( m_pos.x + m_size.x, m_pos.y + m_size.y );
94 }
95 
96 
98 {
99  SCH_BUS_ENTRY_BASE* item = dynamic_cast<SCH_BUS_ENTRY_BASE*>( aItem );
100  wxCHECK_RET( item, wxT( "Cannot swap bus entry data with invalid item." ) );
101 
102  std::swap( m_pos, item->m_pos );
103  std::swap( m_size, item->m_size );
104 }
105 
106 
107 void SCH_BUS_ENTRY_BASE::ViewGetLayers( int aLayers[], int& aCount ) const
108 {
109  aCount = 2;
110  aLayers[0] = Type() == SCH_BUS_BUS_ENTRY_T ? LAYER_BUS : LAYER_WIRE;
111  aLayers[1] = LAYER_SELECTION_SHADOWS;
112 }
113 
114 
116 {
117  EDA_RECT box;
118 
119  box.SetOrigin( m_pos );
120  box.SetEnd( m_End() );
121 
122  box.Normalize();
123  box.Inflate( GetPenSize() / 2 );
124 
125  return box;
126 }
127 
128 
130 {
131  return GetDefaultWireThickness();
132 }
133 
134 
136 {
137  return GetDefaultBusThickness();
138 }
139 
140 
141 void SCH_BUS_WIRE_ENTRY::GetEndPoints( std::vector< DANGLING_END_ITEM >& aItemList )
142 {
143  DANGLING_END_ITEM item( WIRE_ENTRY_END, this, m_pos );
144  aItemList.push_back( item );
145 
146  DANGLING_END_ITEM item1( WIRE_ENTRY_END, this, m_End() );
147  aItemList.push_back( item1 );
148 }
149 
150 
151 void SCH_BUS_BUS_ENTRY::GetEndPoints( std::vector< DANGLING_END_ITEM >& aItemList )
152 {
153  DANGLING_END_ITEM item( BUS_ENTRY_END, this, m_pos );
154  aItemList.push_back( item );
155 
156  DANGLING_END_ITEM item1( BUS_ENTRY_END, this, m_End() );
157  aItemList.push_back( item1 );
158 }
159 
160 
161 void SCH_BUS_ENTRY_BASE::Print( wxDC* aDC, const wxPoint& aOffset )
162 {
164 
165  GRLine( nullptr, aDC, m_pos.x + aOffset.x, m_pos.y + aOffset.y, m_End().x + aOffset.x,
166  m_End().y + aOffset.y, GetPenSize(), color );
167 }
168 
169 
170 void SCH_BUS_ENTRY_BASE::MirrorX( int aXaxis_position )
171 {
172  MIRROR( m_pos.y, aXaxis_position );
173  m_size.y = -m_size.y;
174 }
175 
176 
177 void SCH_BUS_ENTRY_BASE::MirrorY( int aYaxis_position )
178 {
179  MIRROR( m_pos.x, aYaxis_position );
180  m_size.x = -m_size.x;
181 }
182 
183 
185 {
186  RotatePoint( &m_pos, aPosition, 900 );
187  RotatePoint( &m_size.x, &m_size.y, 900 );
188 }
189 
190 
191 bool SCH_BUS_WIRE_ENTRY::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
192  const SCH_SHEET_PATH* aPath )
193 {
194  bool previousStateStart = m_isDanglingStart;
195  bool previousStateEnd = m_isDanglingEnd;
196 
198 
199  // Wires and buses are stored in the list as a pair, start and end. This
200  // variable holds the start position from one iteration so it can be used
201  // when the end position is found.
202  wxPoint seg_start;
203 
204  // Store the connection type and state for the start (0) and end (1)
205  bool has_wire[2] = { false };
206  bool has_bus[2] = { false };
207 
208  for( DANGLING_END_ITEM& each_item : aItemList )
209  {
210  if( each_item.GetItem() == this )
211  continue;
212 
213  switch( each_item.GetType() )
214  {
215  case WIRE_START_END:
216  case WIRE_END_END:
217  if( m_pos == each_item.GetPosition() )
218  has_wire[0] = true;
219  else if( m_End() == each_item.GetPosition() )
220  has_wire[1] = true;
221 
222  break;
223 
224  case BUS_START_END:
225  seg_start = each_item.GetPosition();
226  break;
227 
228  case BUS_END_END:
229  if( IsPointOnSegment( seg_start, each_item.GetPosition(), m_pos ) )
230  has_bus[0] = true;
231  else if( IsPointOnSegment( seg_start, each_item.GetPosition(), m_End() ) )
232  has_bus[1] = true;
233 
234  break;
235 
236  default:
237  break;
238  }
239  }
240 
241  // A bus-wire entry is connected at both ends if it has a bus and a wire on its
242  // ends. Otherwise, we connect only one end (in the case of a wire-wire or bus-bus)
243  if( ( has_wire[0] && has_bus[1] ) || ( has_wire[1] && has_bus[0] ) )
245  else if( has_wire[0] || has_bus[0] )
246  m_isDanglingStart = false;
247  else if( has_wire[1] || has_bus[1] )
248  m_isDanglingEnd = false;
249 
250  return (previousStateStart != m_isDanglingStart) || (previousStateEnd != m_isDanglingEnd);
251 }
252 
253 
254 bool SCH_BUS_BUS_ENTRY::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
255  const SCH_SHEET_PATH* aPath )
256 {
257  bool previousStateStart = m_isDanglingStart;
258  bool previousStateEnd = m_isDanglingEnd;
259 
261 
262  // Wires and buses are stored in the list as a pair, start and end. This
263  // variable holds the start position from one iteration so it can be used
264  // when the end position is found.
265  wxPoint seg_start;
266 
267  for( DANGLING_END_ITEM& each_item : aItemList )
268  {
269  if( each_item.GetItem() == this )
270  continue;
271 
272  switch( each_item.GetType() )
273  {
274  case BUS_START_END:
275  seg_start = each_item.GetPosition();
276  break;
277  case BUS_END_END:
278  if( IsPointOnSegment( seg_start, each_item.GetPosition(), m_pos ) )
279  m_isDanglingStart = false;
280  if( IsPointOnSegment( seg_start, each_item.GetPosition(), m_End() ) )
281  m_isDanglingEnd = false;
282  break;
283  default:
284  break;
285  }
286  }
287 
288  return (previousStateStart != m_isDanglingStart) || (previousStateEnd != m_isDanglingEnd);
289 }
290 
291 
293 {
295 }
296 
297 
298 void SCH_BUS_ENTRY_BASE::GetConnectionPoints( std::vector< wxPoint >& aPoints ) const
299 {
300  aPoints.push_back( m_pos );
301  aPoints.push_back( m_End() );
302 }
303 
304 
306 {
307  return wxString( _( "Bus to Wire Entry" ) );
308 }
309 
310 
312 {
313  return wxString( _( "Bus to Bus Entry" ) );
314 }
315 
316 
318 {
319  return add_line2bus_xpm;
320 }
321 
322 
324 {
325  return add_bus2bus_xpm;
326 }
327 
328 
329 bool SCH_BUS_ENTRY_BASE::HitTest( const wxPoint& aPosition, int aAccuracy ) const
330 {
331  // Insure minimum accuracy
332  if( aAccuracy == 0 )
333  aAccuracy = ( GetPenSize() / 2 ) + 4;
334 
335  return TestSegmentHit( aPosition, m_pos, m_End(), aAccuracy );
336 }
337 
338 
339 bool SCH_BUS_ENTRY_BASE::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
340 {
341  EDA_RECT rect = aRect;
342 
343  rect.Inflate( aAccuracy );
344 
345  if( aContained )
346  return rect.Contains( GetBoundingBox() );
347 
348  return rect.Intersects( GetBoundingBox() );
349 }
350 
351 
353 {
354  aPlotter->SetCurrentLineWidth( GetPenSize() );
355  aPlotter->SetColor( aPlotter->ColorSettings()->GetColor( GetLayer() ) );
356  aPlotter->MoveTo( m_pos );
357  aPlotter->FinishTo( m_End() );
358 }
359 
360 
362 {
363  switch( aShape )
364  {
365  case '\\':
366  if( m_size.y < 0 )
367  m_size.y = -m_size.y;
368  break;
369 
370  case '/':
371  if( m_size.y > 0 )
372  m_size.y = -m_size.y;
373  break;
374  }
375 }
376 
377 
379 {
380  if( GetSize().y < 0 )
381  return '/';
382  else
383  return '\\';
384 }
385 
386 
388 {
389  wxString msg;
390 
391  switch( GetLayer() )
392  {
393  default:
394  case LAYER_WIRE: msg = _( "Wire" ); break;
395  case LAYER_BUS: msg = _( "Bus" ); break;
396  }
397 
398  aList.push_back( MSG_PANEL_ITEM( _( "Bus Entry Type" ), msg, DARKCYAN ) );
399  if( auto conn = Connection( *g_CurrentSheet ) )
400  {
401 #if defined(DEBUG)
402  conn->AppendDebugInfoToMsgPanel( aList );
403 #else
404  conn->AppendInfoToMsgPanel( aList );
405 #endif
406  }
407 }
408 
409 
410 bool SCH_BUS_ENTRY_BASE::operator <( const SCH_ITEM& aItem ) const
411 {
412  if( Type() != aItem.Type() )
413  return Type() < aItem.Type();
414 
415  auto component = static_cast<const SCH_BUS_ENTRY_BASE*>( &aItem );
416 
417  if( GetLayer() != component->GetLayer() )
418  return GetLayer() < component->GetLayer();
419 
420  if( GetPosition().x != component->GetPosition().x )
421  return GetPosition().x < component->GetPosition().x;
422 
423  if( GetPosition().y != component->GetPosition().y )
424  return GetPosition().y < component->GetPosition().y;
425 
426  if( m_End().x != component->m_End().x )
427  return m_End().x < component->m_End().x;
428 
429  return m_End().y < component->m_End().y;
430 }
431 
432 
434 {
435  // Don't generate connections between bus entries and buses, since there is
436  // a connectivity change at that point (e.g. A[7..0] to A7)
437  if( ( aItem->Type() == SCH_LINE_T ) &&
438  ( static_cast<const SCH_LINE*>( aItem )->GetLayer() == LAYER_BUS ) )
439  {
440  return false;
441  }
442 
443  // Don't generate connections between bus entries and bus labels that happen
444  // to land at the same point on the bus wire as this bus entry
445  if( ( aItem->Type() == SCH_LABEL_T ) &&
446  SCH_CONNECTION::IsBusLabel( static_cast<const SCH_LABEL*>( aItem )->GetText() ) )
447  {
448  return false;
449  }
450 
451  // Don't generate connections between two bus-wire entries
452  if( aItem->Type() == SCH_BUS_WIRE_ENTRY_T )
453  return false;
454 
455  return true;
456 }
void FinishTo(const wxPoint &pos)
Definition: plotter.h:283
EDA_UNITS
Definition: common.h:184
void GetMsgPanelInfo(EDA_UNITS aUnits, std::vector< MSG_PANEL_ITEM > &aList) override
Function GetMsgPanelInfo populates aList of MSG_PANEL_ITEM objects with it's internal state for displ...
SCH_LAYER_ID m_Layer
Definition: sch_item.h:152
bool UpdateDanglingState(std::vector< DANGLING_END_ITEM > &aItemList, const SCH_SHEET_PATH *aPath=nullptr) override
Function IsDanglingStateChanged tests the schematic item to aItemList to check if it's dangling state...
int GetDefaultWireThickness()
Default line thickness used to draw/plot wires.
bool doIsConnected(const wxPoint &aPosition) const override
Function doIsConnected provides the object specific test to see if it is connected to aPosition.
PNG memory record (file in memory).
Definition: bitmap_def.h:29
int GetPenSize() const override
Function GetPenSize virtual pure.
void GetConnectionPoints(std::vector< wxPoint > &aPoints) const override
Function GetConnectionPoints add all the connection points for this item to aPoints.
SCH_ITEM * m_connected_bus_item
Pointer to the bus item (usually a bus wire) connected to this bus-wire entry, if it is connected to ...
SCH_ITEM * m_connected_bus_items[2]
Pointer to the bus items (usually bus wires) connected to this bus-bus entry (either or both may be n...
const BITMAP_OPAQUE add_line2bus_xpm[1]
virtual void SetColor(COLOR4D color)=0
static bool IsBusLabel(const wxString &aLabel)
Test if aLabel has a bus notation.
int color
Definition: DXF_plotter.cpp:61
SCH_BUS_WIRE_ENTRY(const wxPoint &pos=wxPoint(0, 0), char shape='\\')
void ViewGetLayers(int aLayers[], int &aCount) const override
Function ViewGetLayers() Returns the all the layers within the VIEW the object is painted on.
void Rotate(wxPoint aPosition) override
Function Rotate rotates the item around aPosition 90 degrees in the clockwise direction.
bool IsPointOnSegment(const wxPoint &aSegStart, const wxPoint &aSegEnd, const wxPoint &aTestPoint)
Test if aTestPoint is on line defined by aSegStart and aSegEnd.
Definition: trigo.cpp:42
void SetOrigin(const wxPoint &pos)
Definition: eda_rect.h:131
const BITMAP_OPAQUE add_bus2bus_xpm[1]
Definition: add_bus2bus.cpp:38
wxPoint m_pos
Definition: sch_bus_entry.h:44
wxSize m_size
Definition: sch_bus_entry.h:45
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:208
bool Contains(const wxPoint &aPoint) const
Function Contains.
void SwapData(SCH_ITEM *aItem) override
Function SwapData swap the internal data structures aItem with the schematic item.
KICAD_T
Enum KICAD_T is the set of class identification values, stored in EDA_ITEM::m_StructType.
Definition: typeinfo.h:78
This file contains miscellaneous commonly used macros and functions.
bool TestSegmentHit(const wxPoint &aRefPoint, wxPoint aStart, wxPoint aEnd, int aDist)
Test if aRefPoint is with aDistance on the line defined by aStart and aEnd.
Definition: trigo.cpp:129
Base class for a bus or wire entry.
Definition: sch_bus_entry.h:41
virtual bool ConnectionPropagatesTo(const EDA_ITEM *aItem) const override
Returns true if this item should propagate connection info to aItem.
EDA_ITEM * Clone() const override
Function Clone creates a duplicate of this item with linked list members set to NULL.
void MIRROR(T &aPoint, const T &aMirrorRef)
Definition: macros.h:123
SCH_BUS_ENTRY_BASE(KICAD_T aType, const wxPoint &pos=wxPoint(0, 0), char shape='\\')
wxString GetSelectMenuText(EDA_UNITS aUnits) const override
Function GetSelectMenuText returns the text to display to be used in the selection clarification cont...
virtual int GetPenSize() const
Function GetPenSize virtual pure.
Definition: sch_item.h:243
EDA_ITEM * Clone() const override
Function Clone creates a duplicate of this item with linked list members set to NULL.
bool IsDangling() const override
#define NULL
SCH_SHEET_PATH * g_CurrentSheet
With the new connectivity algorithm, many more places than before want to know what the current sheet...
COLOR_SETTINGS * ColorSettings()
Definition: plotter.h:145
void SetEnd(int x, int y)
Definition: eda_rect.h:192
bool m_isDanglingStart
Definition: sch_bus_entry.h:46
COLOR4D GetLayerColor(SCH_LAYER_ID aLayer)
Helper for all the old plotting/printing code while it still exists.
void GetEndPoints(std::vector< DANGLING_END_ITEM > &aItemList) override
Function GetEndPoints adds the schematic item end points to aItemList if the item has end points.
char GetBusEntryShape() const
void SetBusEntryShape(char aShape)
SCH_SHEET_PATH.
wxPoint m_End() const
int GetPenSize() const override
Function GetPenSize virtual pure.
void Print(wxDC *aDC, const wxPoint &aOffset) override
Function Print Print a schematic item.
void GRLine(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, int width, COLOR4D Color, wxPenStyle aStyle)
Definition: gr_basic.cpp:230
bool UpdateDanglingState(std::vector< DANGLING_END_ITEM > &aItemList, const SCH_SHEET_PATH *aPath=nullptr) override
Function IsDanglingStateChanged tests the schematic item to aItemList to check if it's dangling state...
SCH_CONNECTION * Connection(const SCH_SHEET_PATH &aPath) const
Retrieves the connection associated with this object in the given sheet Note: the returned value can ...
Definition: sch_item.cpp:128
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes.
SCH_LAYER_ID GetLayer() const
Function GetLayer returns the layer this item is on.
Definition: sch_item.h:224
void MoveTo(const wxPoint &pos)
Definition: plotter.h:273
void Normalize()
Function Normalize ensures that the height ant width are positive.
Base plotter engine class.
Definition: plotter.h:104
COLOR4D GetColor(int aLayer) const
wxSize GetSize() const
Definition: sch_bus_entry.h:77
void GetEndPoints(std::vector< DANGLING_END_ITEM > &aItemList) override
Function GetEndPoints adds the schematic item end points to aItemList if the item has end points.
wxString GetSelectMenuText(EDA_UNITS aUnits) const override
Function GetSelectMenuText returns the text to display to be used in the selection clarification cont...
#define _(s)
Definition: 3d_actions.cpp:33
void MirrorX(int aXaxis_position) override
Function MirrorX mirrors item relative to the X axis about aXaxis_position.
EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
bool m_isDanglingEnd
Definition: sch_bus_entry.h:46
SCH_BUS_BUS_ENTRY(const wxPoint &pos=wxPoint(0, 0), char shape='\\')
void Plot(PLOTTER *aPlotter) override
Function Plot plots the schematic item to aPlotter.
EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boards.
Definition: base_struct.h:166
The common library.
std::vector< MSG_PANEL_ITEM > MSG_PANEL_ITEMS
Definition: msgpanel.h:102
bool Intersects(const EDA_RECT &aRect) const
Function Intersects tests for a common area between rectangles.
bool operator<(const SCH_ITEM &aItem) const override
DANGLING_END_ITEM is a helper class used to store the state of schematic items that can be connected ...
Definition: sch_item.h:76
EDA_MSG_ITEM is used EDA_MSG_PANEL as the item type for displaying messages.
Definition: msgpanel.h:53
BITMAP_DEF GetMenuImage() const override
Function GetMenuImage returns a pointer to an image to be used in menus.
bool HitTest(const wxPoint &aPosition, int aAccuracy=0) const override
Function HitTest tests if aPosition is contained within or on the bounding box of an item.
BITMAP_DEF GetMenuImage() const override
Function GetMenuImage returns a pointer to an image to be used in menus.
void MirrorY(int aYaxis_position) override
Function MirrorY mirrors item relative to the Y axis about aYaxis_position.
SCH_ITEM is a base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:147
int GetDefaultBusThickness()
Default line thickness used to draw/plot busses.
EDA_RECT & Inflate(wxCoord dx, wxCoord dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
KICAD_T Type() const
Function Type()
Definition: base_struct.h:212
virtual void SetCurrentLineWidth(int width, void *aData=NULL)=0
Set the line width for the next drawing.
COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:40
wxPoint GetPosition() const override
Function GetPosition.