KiCad PCB EDA Suite
bus-wire-junction.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, jean-pierre.charras@gipsa-lab.inpg.fr
5  * Copyright (C) 2004-2016 KiCad Developers, see change_log.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 
30 #include <fctsys.h>
31 #include <gr_basic.h>
32 #include <class_drawpanel.h>
33 #include <sch_edit_frame.h>
34 
35 #include <lib_draw_item.h>
36 #include <lib_pin.h>
37 #include <general.h>
38 #include <sch_bus_entry.h>
39 #include <sch_junction.h>
40 #include <sch_line.h>
41 #include <sch_no_connect.h>
42 #include <sch_text.h>
43 #include <sch_component.h>
44 #include <sch_sheet.h>
45 
46 
47 static void AbortCreateNewLine( EDA_DRAW_PANEL* aPanel, wxDC* aDC );
48 static void ComputeBreakPoint( SCH_LINE* segment, const wxPoint& new_pos );
49 
50 static DLIST< SCH_ITEM > s_wires; // when creating a new set of wires,
51  // stores here the new wires.
52 
53 
67 static void RemoveBacktracks( DLIST<SCH_ITEM>& aWires )
68 {
69  EDA_ITEM* first = aWires.GetFirst();
70  std::vector<SCH_LINE*> last_lines;
71 
72  for( EDA_ITEM* p = first; p; )
73  {
74  SCH_LINE *line = static_cast<SCH_LINE*>( p );
75  p = line->Next();
76 
77  if( line->IsNull() )
78  {
79  delete s_wires.Remove( line );
80  continue;
81  }
82 
83  if( !last_lines.empty() )
84  {
85  SCH_LINE* last_line = last_lines[last_lines.size() - 1];
86  bool contiguous = ( last_line->GetEndPoint() == line->GetStartPoint() );
87  bool backtracks = IsPointOnSegment( last_line->GetStartPoint(),
88  last_line->GetEndPoint(), line->GetEndPoint() );
89  bool total_backtrack = ( last_line->GetStartPoint() == line->GetEndPoint() );
90 
91  if( contiguous && backtracks )
92  {
93  if( total_backtrack )
94  {
95  delete s_wires.Remove( last_line );
96  delete s_wires.Remove( line );
97  last_lines.pop_back();
98  }
99  else
100  {
101  last_line->SetEndPoint( line->GetEndPoint() );
102  delete s_wires.Remove( line );
103  }
104  }
105  else
106  {
107  last_lines.push_back( line );
108  }
109  }
110  else
111  {
112  last_lines.push_back( line );
113  }
114  }
115 }
116 
117 
121 static void DrawSegment( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition,
122  bool aErase )
123 {
124  SCH_LINE* segment;
125 
126  if( s_wires.GetCount() == 0 )
127  return;
128 
129  segment = (SCH_LINE*) s_wires.begin();
130  COLOR4D color = GetLayerColor( segment->GetLayer() );
131 
132  if( aErase )
133  {
134  while( segment )
135  {
136  if( !segment->IsNull() ) // Redraw if segment length != 0
137  segment->Draw( aPanel, aDC, wxPoint( 0, 0 ), g_XorMode, color );
138 
139  segment = segment->Next();
140  }
141  }
142 
143  SCH_EDIT_FRAME* frame = (SCH_EDIT_FRAME*) aPanel->GetParent();
144 
145  wxPoint endpos = frame->GetCrossHairPosition();
146 
147  if( frame->GetForceHVLines() ) /* Coerce the line to vertical or horizontal one: */
148  ComputeBreakPoint( (SCH_LINE*) s_wires.GetLast()->Back(), endpos );
149  else
150  ( (SCH_LINE*) s_wires.GetLast() )->SetEndPoint( endpos );
151 
152  segment = (SCH_LINE*) s_wires.begin();
153 
154  while( segment )
155  {
156  if( !segment->IsNull() ) // Redraw if segment length != 0
157  segment->Draw( aPanel, aDC, wxPoint( 0, 0 ), g_XorMode, color );
158 
159  segment = segment->Next();
160  }
161 }
162 
163 
164 void SCH_EDIT_FRAME::BeginSegment( wxDC* DC, int type )
165 {
166  SCH_LINE* segment;
167  SCH_LINE* nextSegment;
168  wxPoint cursorpos = GetCrossHairPosition();
169 
170  // We should know if a segment is currently in progress
171  segment = (SCH_LINE*) GetScreen()->GetCurItem();
172  if( segment ) // a current item exists, but not necessary a currently edited item
173  {
174  if( !segment->GetFlags() || ( segment->Type() != SCH_LINE_T ) )
175  {
176  if( segment->GetFlags() )
177  {
178  wxLogDebug( wxT( "BeginSegment: item->GetFlags()== %X" ),
179  segment->GetFlags() );
180  }
181  // no wire, bus or graphic line in progress
182  segment = NULL;
183  }
184  }
185 
186  if( !segment ) // first point : Create the first wire or bus segment
187  {
188  switch( type )
189  {
190  default:
191  segment = new SCH_LINE( cursorpos, LAYER_NOTES );
192  break;
193 
194  case LAYER_WIRE:
195  segment = new SCH_LINE( cursorpos, LAYER_WIRE );
196 
197  /* A junction will be created later, when we'll know the
198  * segment end position, and if the junction is really needed */
199  break;
200 
201  case LAYER_BUS:
202  segment = new SCH_LINE( cursorpos, LAYER_BUS );
203  break;
204  }
205 
206  segment->SetFlags( IS_NEW );
207  s_wires.PushBack( segment );
208  GetScreen()->SetCurItem( segment );
209 
210  // We need 2 segments to go from a given start pin to an end point when the horizontal
211  // and vertical lines only switch is on.
212  if( GetForceHVLines() )
213  {
214  nextSegment = new SCH_LINE( *segment );
215  nextSegment->SetFlags( IS_NEW );
216  s_wires.PushBack( nextSegment );
217  GetScreen()->SetCurItem( nextSegment );
218  }
219 
221  SetRepeatItem( NULL );
222  }
223  else // A segment is in progress: terminates the current segment and add a new segment.
224  {
225  SCH_LINE* prevSegment = segment->Back();
226 
227  // Be aware prevSegment can be null when the horizontal and vertical lines only switch is off
228  // when we create the first segment.
229 
230  if( !GetForceHVLines() )
231  {
232  // If only one segment is needed and it has a zero length, do not create a new one.
233  if( segment->IsNull() )
234  return;
235  }
236  else
237  {
238  wxCHECK_RET( prevSegment != NULL, wxT( "Failed to create second line segment." ) );
239 
240  // If two segments are required and they both have zero length, do not
241  // create a new one.
242  if( prevSegment && prevSegment->IsNull() && segment->IsNull() )
243  return;
244  }
245 
246  m_canvas->CallMouseCapture( DC, wxDefaultPosition, false );
247 
248  // Terminate the command if the end point is on a pin, junction, or another wire or bus.
249  if( GetScreen()->IsTerminalPoint( cursorpos, segment->GetLayer() ) )
250  {
251  EndSegment();
252  return;
253  }
254 
255  // Create a new segment, and chain it after the current new segment.
256  nextSegment = new SCH_LINE( *segment );
257  nextSegment->SetStartPoint( cursorpos );
258  s_wires.PushBack( nextSegment );
259 
260  segment->SetEndPoint( cursorpos );
261  segment->ClearFlags( IS_NEW );
262  segment->SetFlags( SELECTED );
263  nextSegment->SetFlags( IS_NEW );
264  GetScreen()->SetCurItem( nextSegment );
265  m_canvas->CallMouseCapture( DC, wxDefaultPosition, false );
266  }
267 }
268 
269 
270 void SCH_EDIT_FRAME::GetSchematicConnections( std::vector< wxPoint >& aConnections )
271 {
272  for( SCH_ITEM* item = GetScreen()->GetDrawItems(); item; item = item->Next() )
273  {
274  // Avoid items that are changing
275  if( !( item->GetFlags() & ( IS_DRAGGED | IS_MOVED | IS_DELETED ) ) )
276  item->GetConnectionPoints( aConnections );
277  }
278 
279  // We always have some overlapping connection points. Drop duplicates here
280  std::sort( aConnections.begin(), aConnections.end(),
281  []( const wxPoint& a, const wxPoint& b ) -> bool
282  { return a.x < b.x || (a.x == b.x && a.y < b.y); } );
283  aConnections.erase( unique( aConnections.begin(), aConnections.end() ), aConnections.end() );
284 }
285 
286 
288 {
289  SCH_SCREEN* screen = GetScreen();
290  SCH_LINE* segment = (SCH_LINE*) screen->GetCurItem();
291  PICKED_ITEMS_LIST itemList;
292 
293  if( segment == NULL || segment->Type() != SCH_LINE_T || !segment->IsNew() )
294  return;
295 
296  // Remove segments backtracking over others
297  RemoveBacktracks( s_wires );
298 
299  if( s_wires.GetCount() == 0 )
300  return;
301 
302  // Collect the possible connection points for the new lines
303  std::vector< wxPoint > connections;
304  std::vector< wxPoint > new_ends;
305  GetSchematicConnections( connections );
306 
307  // Check each new segment for possible junctions and add/split if needed
308  for( SCH_ITEM* wire = s_wires.GetFirst(); wire; wire=wire->Next() )
309  {
310  SCH_LINE* test_line = (SCH_LINE*) wire;
311  if( wire->GetFlags() & SKIP_STRUCT )
312  continue;
313 
314  wire->GetConnectionPoints( new_ends );
315 
316  for( auto i : connections )
317  {
318  if( IsPointOnSegment( test_line->GetStartPoint(), test_line->GetEndPoint(), i ) )
319  {
320  new_ends.push_back( i );
321  }
322  }
323  itemList.PushItem( ITEM_PICKER( wire, UR_NEW ) );
324  }
325 
326  // Get the last non-null wire (this is the last created segment).
327  SetRepeatItem( segment = (SCH_LINE*) s_wires.GetLast() );
328 
329  // Add the new wires
330  screen->Append( s_wires );
331  SaveCopyInUndoList(itemList, UR_NEW);
332 
333  // Correct and remove segments that need to be merged.
334  SchematicCleanUp( true );
335  for( auto i : new_ends )
336  {
337  if( screen->IsJunctionNeeded( i, true ) )
338  AddJunction( i, true );
339  }
340 
341  screen->TestDanglingEnds();
342  screen->ClearDrawingState();
343  screen->SetCurItem( NULL );
344  m_canvas->EndMouseCapture( -1, -1, wxEmptyString, false );
345  OnModify();
346 }
347 
348 
359 static void ComputeBreakPoint( SCH_LINE* aSegment, const wxPoint& aPosition )
360 {
361  wxCHECK_RET( aSegment != NULL, wxT( "Cannot compute break point of NULL line segment." ) );
362 
363  SCH_LINE* nextSegment = aSegment->Next();
364  wxPoint midPoint = aPosition;
365 
366  wxCHECK_RET( nextSegment != NULL,
367  wxT( "Cannot compute break point of NULL second line segment." ) );
368 
369 #if 0
370  if( ABS( midPoint.x - aSegment->GetStartPoint().x ) <
371  ABS( midPoint.y - aSegment->GetStartPoint().y ) )
372  midPoint.x = aSegment->GetStartPoint().x;
373  else
374  midPoint.y = aSegment->GetStartPoint().y;
375 #else
376  int iDx = aSegment->GetEndPoint().x - aSegment->GetStartPoint().x;
377  int iDy = aSegment->GetEndPoint().y - aSegment->GetStartPoint().y;
378 
379  if( iDy != 0 ) // keep the first segment orientation (currently horizontal)
380  {
381  midPoint.x = aSegment->GetStartPoint().x;
382  }
383  else if( iDx != 0 ) // keep the first segment orientation (currently vertical)
384  {
385  midPoint.y = aSegment->GetStartPoint().y;
386  }
387  else
388  {
389  if( std::abs( midPoint.x - aSegment->GetStartPoint().x ) <
390  std::abs( midPoint.y - aSegment->GetStartPoint().y ) )
391  midPoint.x = aSegment->GetStartPoint().x;
392  else
393  midPoint.y = aSegment->GetStartPoint().y;
394  }
395 #endif
396 
397  aSegment->SetEndPoint( midPoint );
398  nextSegment->SetStartPoint( midPoint );
399  nextSegment->SetEndPoint( aPosition );
400 }
401 
402 
404 {
405  SCH_SCREEN* screen = GetScreen();
406 
407  SetRepeatItem( NULL );
408 
409  if( ( screen->GetCurItem() == NULL ) || !screen->GetCurItem()->IsNew() )
410  return;
411 
412  DrawSegment( m_canvas, DC, wxDefaultPosition, false );
413 
414  screen->Remove( screen->GetCurItem() );
416  screen->SetCurItem( NULL );
417 }
418 
419 
421 {
422  DLIST< SCH_ITEM > oldWires;
423 
424  oldWires.SetOwnership( false ); // Prevent DLIST for deleting items in destructor.
425  GetScreen()->ExtractWires( oldWires, true );
426 
427  if( oldWires.GetCount() != 0 )
428  {
429  PICKED_ITEMS_LIST oldItems;
430 
431  oldItems.m_Status = UR_WIRE_IMAGE;
432 
433  while( oldWires.GetCount() != 0 )
434  {
435  ITEM_PICKER picker = ITEM_PICKER( oldWires.PopFront(), UR_WIRE_IMAGE );
436  oldItems.PushItem( picker );
437  }
438 
439  SaveCopyInUndoList( oldItems, UR_WIRE_IMAGE );
440  }
441 }
442 
443 
444 bool SCH_EDIT_FRAME::TrimWire( const wxPoint& aStart, const wxPoint& aEnd, bool aAppend )
445 {
446  SCH_LINE* line;
447  SCH_ITEM* next_item = NULL;
448  bool retval = false;
449 
450  if( aStart == aEnd )
451  return retval;
452 
453  for( SCH_ITEM* item = GetScreen()->GetDrawItems(); item; item = next_item )
454  {
455  next_item = item->Next();
456 
457  // Don't remove wires that are already deleted, are currently being
458  // dragged or are just created
459  if( item->GetFlags() &
461  continue;
462 
463  if( item->Type() != SCH_LINE_T || item->GetLayer() != LAYER_WIRE )
464  continue;
465 
466  line = (SCH_LINE*) item;
467  if( !IsPointOnSegment( line->GetStartPoint(), line->GetEndPoint(), aStart ) ||
468  !IsPointOnSegment( line->GetStartPoint(), line->GetEndPoint(), aEnd ) )
469  continue;
470 
471  // Step 1: break the segment on one end. return_line remains line if not broken.
472  // Ensure that *line points to the segment containing aEnd
473  SCH_LINE* return_line = line;
474  aAppend |= BreakSegment( line, aStart, aAppend, &return_line );
475  if( IsPointOnSegment( return_line->GetStartPoint(), return_line->GetEndPoint(), aEnd ) )
476  line = return_line;
477 
478  // Step 2: break the remaining segment. return_line remains line if not broken.
479  // Ensure that *line _also_ contains aStart. This is our overlapping segment
480  aAppend |= BreakSegment( line, aEnd, aAppend, &return_line );
481  if( IsPointOnSegment( return_line->GetStartPoint(), return_line->GetEndPoint(), aStart ) )
482  line = return_line;
483 
484  SaveCopyInUndoList( (SCH_ITEM*)line, UR_DELETED, aAppend );
485  GetScreen()->Remove( (SCH_ITEM*)line );
486  aAppend = true;
487  retval = true;
488  }
489 
490  return retval;
491 }
492 
493 
495 {
496  SCH_ITEM* item = NULL;
497  SCH_ITEM* secondItem = NULL;
498  PICKED_ITEMS_LIST itemList;
499  SCH_SCREEN* screen = GetScreen();
500 
501  auto remove_item = [ &itemList ]( SCH_ITEM* aItem ) -> void
502  {
503  aItem->SetFlags( STRUCT_DELETED );
504  itemList.PushItem( ITEM_PICKER( aItem, UR_DELETED ) );
505  };
506 
507  BreakSegmentsOnJunctions( true );
508 
509  for( item = screen->GetDrawItems(); item; item = item->Next() )
510  {
511  if( ( item->Type() != SCH_LINE_T )
512  && ( item->Type() != SCH_JUNCTION_T )
513  && ( item->Type() != SCH_NO_CONNECT_T ) )
514  continue;
515 
516  if( item->GetFlags() & STRUCT_DELETED )
517  continue;
518 
519  // Remove unneeded junctions
520  if( ( item->Type() == SCH_JUNCTION_T )
521  && ( !screen->IsJunctionNeeded( item->GetPosition() ) ) )
522  {
523  remove_item( item );
524  continue;
525  }
526 
527  // Remove zero-length lines
528  if( item->Type() == SCH_LINE_T
529  && ( (SCH_LINE*) item )->IsNull() )
530  {
531  remove_item( item );
532  continue;
533  }
534 
535  for( secondItem = item->Next(); secondItem; secondItem = secondItem->Next() )
536  {
537  if( item->Type() != secondItem->Type() || ( secondItem->GetFlags() & STRUCT_DELETED ) )
538  continue;
539 
540  // Merge overlapping lines
541  if( item->Type() == SCH_LINE_T )
542  {
543  SCH_LINE* firstLine = (SCH_LINE*) item;
544  SCH_LINE* secondLine = (SCH_LINE*) secondItem;
545  SCH_LINE* line = NULL;
546  bool needed = false;
547 
548  if( !secondLine->IsParallel( firstLine ) )
549  continue;
550 
551  // Remove identical lines
552  if( firstLine->IsEndPoint( secondLine->GetStartPoint() )
553  && firstLine->IsEndPoint( secondLine->GetEndPoint() ) )
554  {
555  remove_item( secondItem );
556  continue;
557  }
558 
559  // If the end points overlap, check if we still need the junction
560  if( secondLine->IsEndPoint( firstLine->GetStartPoint() ) )
561  needed = screen->IsJunctionNeeded( firstLine->GetStartPoint() );
562  else if( secondLine->IsEndPoint( firstLine->GetEndPoint() ) )
563  needed = screen->IsJunctionNeeded( firstLine->GetEndPoint() );
564 
565  if( !needed && ( line = (SCH_LINE*) secondLine->MergeOverlap( firstLine ) ) )
566  {
567  remove_item( item );
568  remove_item( secondItem );
569  itemList.PushItem( ITEM_PICKER( line, UR_NEW ) );
570  screen->Append( (SCH_ITEM*) line );
571  break;
572  }
573  }
574  // Remove duplicate junctions and no-connects
575  else if( secondItem->GetPosition() == item->GetPosition() )
576  remove_item( secondItem );
577  }
578  }
579 
580  for( item = screen->GetDrawItems(); item; item = secondItem )
581  {
582  secondItem = item->Next();
583 
584  if( item->GetFlags() & STRUCT_DELETED )
585  screen->Remove( item );
586  }
587 
588  SaveCopyInUndoList( itemList, UR_CHANGED, aAppend );
589 
590  return !!( itemList.GetCount() );
591 }
592 
593 
594 bool SCH_EDIT_FRAME::BreakSegment( SCH_LINE* aSegment, const wxPoint& aPoint, bool aAppend,
595  SCH_LINE** aNewSegment )
596 {
597  if( !IsPointOnSegment( aSegment->GetStartPoint(), aSegment->GetEndPoint(), aPoint )
598  || aSegment->IsEndPoint( aPoint ) )
599  return false;
600 
601  SaveCopyInUndoList( aSegment, UR_CHANGED, aAppend );
602  SCH_LINE* newSegment = new SCH_LINE( *aSegment );
603  SaveCopyInUndoList( newSegment, UR_NEW, true );
604 
605  newSegment->SetStartPoint( aPoint );
606  aSegment->SetEndPoint( aPoint );
607  GetScreen()->Append( newSegment );
608 
609  if( aNewSegment )
610  *aNewSegment = newSegment;
611 
612  return true;
613 }
614 
615 
616 bool SCH_EDIT_FRAME::BreakSegments( const wxPoint& aPoint, bool aAppend )
617 {
618  bool brokenSegments = false;
619 
620  for( SCH_ITEM* segment = GetScreen()->GetDrawItems(); segment; segment = segment->Next() )
621  {
622  if( ( segment->Type() != SCH_LINE_T ) || ( segment->GetLayer() == LAYER_NOTES ) )
623  continue;
624 
625  brokenSegments |= BreakSegment( (SCH_LINE*) segment, aPoint, aAppend || brokenSegments );
626  }
627 
628  return brokenSegments;
629 }
630 
631 
633 {
634  bool brokenSegments = false;
635 
636  for( SCH_ITEM* item = GetScreen()->GetDrawItems(); item; item = item->Next() )
637  {
638  if( item->Type() == SCH_JUNCTION_T )
639  {
640  SCH_JUNCTION* junction = ( SCH_JUNCTION* ) item;
641 
642  if( BreakSegments( junction->GetPosition(), brokenSegments || aAppend ) )
643  brokenSegments = true;
644  }
645  else
646  {
647  SCH_BUS_ENTRY_BASE* busEntry = dynamic_cast<SCH_BUS_ENTRY_BASE*>( item );
648  if( busEntry )
649  {
650  if( BreakSegments( busEntry->GetPosition(), brokenSegments || aAppend )
651  || BreakSegments( busEntry->m_End(), brokenSegments || aAppend ) )
652  brokenSegments = true;
653  }
654  }
655  }
656 
657  return brokenSegments;
658 }
659 
660 
661 void SCH_EDIT_FRAME::DeleteJunction( SCH_ITEM* aJunction, bool aAppend )
662 {
663  SCH_SCREEN* screen = GetScreen();
664  PICKED_ITEMS_LIST itemList;
665 
666  auto remove_item = [ & ]( SCH_ITEM* aItem ) -> void
667  {
668  aItem->SetFlags( STRUCT_DELETED );
669  itemList.PushItem( ITEM_PICKER( aItem, UR_DELETED ) );
670  screen->Remove( aItem );
671  };
672 
673  remove_item( aJunction );
674 
675  for( SCH_ITEM* item = screen->GetDrawItems(); item; item = item->Next() )
676  {
677  SCH_LINE* firstLine = dynamic_cast<SCH_LINE*>( item );
678 
679  if( !firstLine || !firstLine->IsEndPoint( aJunction->GetPosition() )
680  || ( firstLine->GetFlags() & STRUCT_DELETED ) )
681  continue;
682 
683  for( SCH_ITEM* secondItem = item->Next(); secondItem; secondItem = secondItem->Next() )
684  {
685  SCH_LINE* secondLine = dynamic_cast<SCH_LINE*>( secondItem );
686 
687  if( !secondLine || !secondLine->IsEndPoint( aJunction->GetPosition() )
688  || ( secondItem->GetFlags() & STRUCT_DELETED )
689  || !secondLine->IsParallel( firstLine ) )
690  continue;
691 
692 
693  // Remove identical lines
694  if( firstLine->IsEndPoint( secondLine->GetStartPoint() )
695  && firstLine->IsEndPoint( secondLine->GetEndPoint() ) )
696  {
697  remove_item( secondItem );
698  continue;
699  }
700 
701  // Try to merge the remaining lines
702  if( SCH_LINE* line = (SCH_LINE*) secondLine->MergeOverlap( firstLine ) )
703  {
704  remove_item( item );
705  remove_item( secondItem );
706  itemList.PushItem( ITEM_PICKER( line, UR_NEW ) );
707  screen->Append( (SCH_ITEM*) line );
708  break;
709  }
710  }
711  }
712 
713  SaveCopyInUndoList( itemList, UR_DELETED, aAppend );
714 
715  SCH_ITEM* nextitem;
716  for( SCH_ITEM* item = screen->GetDrawItems(); item; item = nextitem )
717  {
718  nextitem = item->Next();
719 
720  if( item->GetFlags() & STRUCT_DELETED )
721  screen->Remove( item );
722  }
723 }
724 
725 
726 SCH_JUNCTION* SCH_EDIT_FRAME::AddJunction( const wxPoint& aPosition, bool aAppend )
727 {
728  SCH_JUNCTION* junction = new SCH_JUNCTION( aPosition );
729  SCH_SCREEN* screen = GetScreen();
730  bool broken_segments = false;
731 
732  screen->Append( junction );
733  broken_segments = BreakSegments( aPosition, aAppend );
734  screen->TestDanglingEnds();
735  OnModify();
736  SaveCopyInUndoList( junction, UR_NEW, broken_segments || aAppend );
737  return junction;
738 }
739 
740 
742 {
743  SCH_NO_CONNECT* no_connect = new SCH_NO_CONNECT( aPosition );
744 
745  SetRepeatItem( no_connect );
746  GetScreen()->Append( no_connect );
748  OnModify();
749  m_canvas->Refresh();
750  SaveCopyInUndoList( no_connect, UR_NEW );
751  return no_connect;
752 }
753 
754 
755 /* Abort function for wire, bus or line creation
756  */
757 static void AbortCreateNewLine( EDA_DRAW_PANEL* aPanel, wxDC* aDC )
758 {
759  SCH_SCREEN* screen = (SCH_SCREEN*) aPanel->GetScreen();
760 
761  if( screen->GetCurItem() )
762  {
763  s_wires.DeleteAll(); // Free the list, for a future usage
764  screen->SetCurItem( NULL );
765  aPanel->Refresh();
766  }
767  else
768  {
769  SCH_EDIT_FRAME* parent = ( SCH_EDIT_FRAME* ) aPanel->GetParent();
770  parent->SetRepeatItem( NULL );
771  }
772 
773  // Clear flags used in edit functions.
774  screen->ClearDrawingState();
775 }
776 
777 
779 {
780  SCH_ITEM* repeater = GetRepeatItem();
781 
782  if( !repeater )
783  return;
784 
785  //D( repeater>Show( 0, std::cout ); )
786 
787  // clone the repeater, move it, insert into display list, then save a copy
788  // via SetRepeatItem();
789 
790  SCH_ITEM* my_clone = (SCH_ITEM*) repeater->Clone();
791 
792  // If cloning a component then put into 'move' mode.
793  if( my_clone->Type() == SCH_COMPONENT_T )
794  {
795  wxPoint pos = GetCrossHairPosition() -
796  ( (SCH_COMPONENT*) my_clone )->GetPosition();
797 
798  my_clone->SetFlags( IS_NEW );
799  ( (SCH_COMPONENT*) my_clone )->SetTimeStamp( GetNewTimeStamp() );
800  my_clone->Move( pos );
801  my_clone->Draw( m_canvas, DC, wxPoint( 0, 0 ), g_XorMode );
802  PrepareMoveItem( my_clone, DC );
803  }
804  else
805  {
806  my_clone->Move( GetRepeatStep() );
807 
808  if( my_clone->CanIncrementLabel() )
809  ( (SCH_TEXT*) my_clone )->IncrementLabel( GetRepeatDeltaLabel() );
810 
811  GetScreen()->Append( my_clone );
812 
813  if( my_clone->IsConnectable() )
814  {
816  m_canvas->Refresh();
817  }
818  else
819  {
820  my_clone->Draw( m_canvas, DC, wxPoint( 0, 0 ), GR_DEFAULT_DRAWMODE );
821  }
822 
823  SaveCopyInUndoList( my_clone, UR_NEW );
824  my_clone->ClearFlags();
825  }
826 
827  // clone my_clone, now that it has been moved, thus saving new position.
828  SetRepeatItem( my_clone );
829 }
void GetConnectionPoints(std::vector< wxPoint > &aPoints) const override
Function GetConnectionPoints add all the connection points for this item to aPoints.
Definition: sch_line.cpp:603
Definition of the SCH_SHEET class for Eeschema.
GR_DRAWMODE g_XorMode
Definition: gr_basic.cpp:73
void RepeatDrawItem(wxDC *DC)
Repeat the last item placement if the last item was a bus, bus entry, label, or component.
SCH_JUNCTION * AddJunction(const wxPoint &aPosition, bool aPutInUndoList=false)
Add a new junction at aPosition.
KICAD_T Type() const
Function Type()
Definition: base_struct.h:209
bool IsPointOnSegment(const wxPoint &aSegStart, const wxPoint &aSegEnd, const wxPoint &aTestPoint)
Function IsPointOnSegment.
Definition: trigo.cpp:39
STATUS_FLAGS GetFlags() const
Definition: base_struct.h:266
virtual bool CanIncrementLabel() const
bool SchematicCleanUp(bool aAppend=false)
Performs routine schematic cleaning including breaking wire and buses and deleting identical objects ...
T * Remove(T *aElement)
Function Remove removes aElement from the list, but does not delete it.
Definition: dlist.h:211
void GetSchematicConnections(std::vector< wxPoint > &aConnections)
Collects a unique list of all possible connection points in the schematic.
virtual void Refresh(bool eraseBackground=true, const wxRect *rect=NULL) override
Update the board display after modifying it bu a python script (note: it is automatically called by a...
Definition: draw_panel.cpp:338
SCH_ITEM * GetRepeatItem() const
Return the item which is to be repeated with the insert key.
static void RemoveBacktracks(DLIST< SCH_ITEM > &aWires)
In a contiguous list of wires, remove wires that backtrack over the previous wire.
bool IsNew() const
Definition: base_struct.h:227
bool GetForceHVLines() const
bool IsJunctionNeeded(const wxPoint &aPosition, bool aNew=false)
Test if a junction is required for the items at aPosition on the screen.
Definition: sch_screen.cpp:346
void OnModify()
Must be called after a schematic change in order to set the "modify" flag of the current screen* and ...
virtual EDA_ITEM * Clone() const
Function Clone creates a duplicate of this item with linked list members set to NULL.
const wxPoint GetRepeatStep() const
#define SKIP_STRUCT
flag indicating that the structure should be ignored
Definition: base_struct.h:120
bool IsParallel(SCH_LINE *aLine)
Definition: sch_line.cpp:386
int color
Definition: DXF_plotter.cpp:62
bool BreakSegments(const wxPoint &aPoint, bool aAppend=false)
Checks every wire and bus for a intersection at aPoint and break into two segments at aPoint if an in...
bool BreakSegmentsOnJunctions(bool aApped=false)
Tests all junctions and bus entries in the schematic for intersections with wires and buses and break...
static void DrawSegment(EDA_DRAW_PANEL *aPanel, wxDC *aDC, const wxPoint &aPosition, bool aErase)
Mouse capture callback for drawing line segments.
void EndMouseCapture(int aId=-1, int aCursorId=-1, const wxString &aTitle=wxEmptyString, bool aCallEndFunc=true)
Function EndMouseCapture ends mouse a capture.
T * begin() const
Definition: dlist.h:218
void BeginSegment(wxDC *DC, int type)
Creates a new segment ( WIRE, BUS ) or terminates the current segment in progress.
void PushItem(const ITEM_PICKER &aItem)
Function PushItem pushes aItem to the top of the list.
wxPoint GetEndPoint() const
Definition: sch_line.h:80
Schematic editor (Eeschema) main window.
SCH_LINE * Next() const
Definition: sch_line.h:61
SCH_LAYER_ID GetLayer() const
Function GetLayer returns the layer this item is on.
void Remove(SCH_ITEM *aItem)
Remove aItem from the schematic associated with this screen.
Definition: sch_screen.cpp:169
wxPoint m_End() const
int GetRepeatDeltaLabel() const
EDA_ITEM * Next() const
Definition: base_struct.h:217
void DeleteAll()
Function DeleteAll deletes all items on the list and leaves the list empty.
Definition: dlist.cpp:41
COLOR4D GetLayerColor(SCH_LAYER_ID aLayer)
Definition: eeschema.cpp:167
void EndSegment()
Terminate a bus, wire, or line creation.
#define abs(a)
Definition: auxiliary.h:84
SCH_ITEM * Next() const
void PrepareMoveItem(SCH_ITEM *aItem, wxDC *aDC)
Start moving aItem using the mouse.
Definition: schedit.cpp:781
void SetRepeatItem(SCH_ITEM *aItem)
Clone aItem and owns that clone in this container.
void SetEndPoint(const wxPoint &aPosition)
Definition: sch_line.h:82
SCH_ITEM * Back() const
void PushBack(T *aNewElement)
Function PushBack puts aNewElement at the end of the list sequence.
Definition: dlist.h:250
wxPoint GetStartPoint() const
Definition: sch_line.h:76
Base class for a bus or wire entry.
Definition: sch_bus_entry.h:41
#define IS_NEW
New item, just created.
Definition: base_struct.h:109
SCH_SCREEN * GetScreen() const override
Function GetScreen returns a pointer to a BASE_SCREEN or one of its derivatives.
#define IS_DRAGGED
Item being dragged.
Definition: base_struct.h:111
#define SELECTED
Definition: base_struct.h:116
timestamp_t GetNewTimeStamp()
Definition: common.cpp:167
virtual wxPoint GetPosition() const =0
Function GetPosition.
void SetFlags(STATUS_FLAGS aMask)
Definition: base_struct.h:264
void DeleteCurrentSegment(wxDC *DC)
Erase the last segment at the current mouse position.
wxPoint GetPosition() const override
Function GetPosition.
Definition: sch_junction.h:94
T * GetLast() const
Function GetLast returns the last T* in the list without removing it, or NULL if the list is empty...
Definition: dlist.h:170
SCH_ITEM * GetCurItem() const
Return the currently selected SCH_ITEM, overriding BASE_SCREEN::GetCurItem().
Definition: sch_screen.h:174
#define IS_DELETED
Definition: base_struct.h:112
virtual bool IsConnectable() const
Function IsConnectable returns true if the schematic item can connect to another schematic item...
void SetStartPoint(const wxPoint &aPosition)
Definition: sch_line.h:78
void SaveCopyInUndoList(SCH_ITEM *aItemToCopy, UNDO_REDO_T aTypeCommand, bool aAppend=false, const wxPoint &aTransformPoint=wxPoint(0, 0))
Create a copy of the current schematic item, and put it in the undo list.
void CallMouseCapture(wxDC *aDC, const wxPoint &aPosition, bool aErase)
Function CallMouseCapture calls the mouse capture callback.
T * GetFirst() const
Function GetFirst returns the first T* in the list without removing it, or NULL if the list is empty...
Definition: dlist.h:163
#define STRUCT_DELETED
flag indication structures to be erased
Definition: base_struct.h:118
EDA_DRAW_FRAME * GetParent() const
Definition: draw_panel.cpp:180
Class PICKED_ITEMS_LIST is a holder to handle information on schematic or board items.
void SetMouseCaptureCallback(MOUSE_CAPTURE_CALLBACK aMouseCaptureCallback)
bool IsNull() const
Definition: sch_line.h:74
unsigned GetCount() const
Function GetCount.
static void AbortCreateNewLine(EDA_DRAW_PANEL *aPanel, wxDC *aDC)
EDA_DRAW_PANEL * m_canvas
The area to draw on.
Definition: draw_frame.h:98
bool IsEndPoint(const wxPoint &aPoint) const
Definition: sch_line.h:69
SCH_ITEM * GetDrawItems() const
Definition: sch_screen.h:138
#define GR_DEFAULT_DRAWMODE
Definition: general.h:70
Definition the SCH_COMPONENT class for Eeschema.
EDA_ITEM * MergeOverlap(SCH_LINE *aLine)
Check line against aLine to see if it overlaps and merge if it does.
Definition: sch_line.cpp:399
Segment description base class to describe items which have 2 end points (track, wire, draw line ...)
Definition: sch_line.h:41
void Append(SCH_ITEM *aItem)
Definition: sch_screen.h:140
void DeleteJunction(SCH_ITEM *aItem, bool aAppend=false)
Removes a given junction and heals any wire segments under the junction.
bool TestDanglingEnds()
Test all of the connectable objects in the schematic for unused connection points.
Definition: sch_screen.cpp:913
void SetCurItem(SCH_ITEM *aItem)
Sets the currently selected object, m_CurrentItem.
Definition: sch_screen.h:182
size_t i
Definition: json11.cpp:597
Class SCH_COMPONENT describes a real schematic component.
Definition: sch_component.h:69
BASE_SCREEN * GetScreen()
Definition: draw_panel.cpp:193
Class EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boa...
Definition: base_struct.h:162
bool TrimWire(const wxPoint &aStart, const wxPoint &aEnd, bool aAppend=true)
If any single wire passes through both points, remove the portion between the two points...
void ExtractWires(DLIST< SCH_ITEM > &aList, bool aCreateCopy)
Extracts the old wires, junctions and buses.
Definition: sch_screen.cpp:250
SCH_LINE * Back() const
Definition: sch_line.h:62
void ClearFlags(STATUS_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: base_struct.h:265
unsigned GetCount() const
Function GetCount returns the number of elements in the list.
Definition: dlist.h:126
void SetOwnership(bool Iown)
Function SetOwnership controls whether the list owns the objects and is responsible for deleteing the...
Definition: dlist.h:119
bool BreakSegment(SCH_LINE *aSegment, const wxPoint &aPoint, bool aAppend=false, SCH_LINE **aNewSegment=NULL)
Breaks a single segment into two at the specified point.
void ClearDrawingState()
Clear the state flags of all the items in the screen.
Definition: sch_screen.cpp:582
void Draw(EDA_DRAW_PANEL *aPanel, wxDC *aDC, const wxPoint &aOffset, GR_DRAWMODE aDrawMode, COLOR4D aColor=COLOR4D::UNSPECIFIED) override
Function Draw Draw a schematic item.
Definition: sch_line.cpp:306
void SetMouseCapture(MOUSE_CAPTURE_CALLBACK aMouseCaptureCallback, END_MOUSE_CAPTURE_CALLBACK aEndMouseCaptureCallback)
Function SetMouseCapture sets the mouse capture and end mouse capture callbacks to aMouseCaptureCallb...
SCH_NO_CONNECT * AddNoConnect(const wxPoint &aPosition)
Add no connect item to the current schematic sheet at aPosition.
wxPoint GetCrossHairPosition(bool aInvertY=false) const
Function GetCrossHairPosition return the current cross hair position in logical (drawing) coordinates...
Class SCH_ITEM is a base class for any item which can be embedded within the SCHEMATIC container clas...
Implementation of the label properties dialog.
static void ComputeBreakPoint(SCH_LINE *segment, const wxPoint &new_pos)
Function ComputeBreakPoint computes the middle coordinate for 2 segments from the start point to aPos...
virtual void Draw(EDA_DRAW_PANEL *aPanel, wxDC *aDC, const wxPoint &aOffset, GR_DRAWMODE aDrawMode, COLOR4D aColor=COLOR4D::UNSPECIFIED)=0
Function Draw Draw a schematic item.
T * PopFront()
Definition: dlist.h:221
void SaveWireImage()
Save a copy of the current wire image in the undo list.
static DLIST< SCH_ITEM > s_wires
Class COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:39
wxPoint GetPosition() const override
Function GetPosition.
#define IS_MOVED
Item being moved.
Definition: base_struct.h:108
virtual void Move(const wxPoint &aMoveVector)=0
Function Move moves the item by aMoveVector to a new position.