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_SCREEN* aScreen, SCH_LINE* aSegment, 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( frame->GetScreen(), (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 
349 // A helper function to find any sheet pins at the specified position.
350 static const SCH_SHEET_PIN* getSheetPin( SCH_SCREEN* aScreen, const wxPoint& aPosition )
351 {
352  for( SCH_ITEM* item = aScreen->GetDrawItems(); item; item = item->Next() )
353  {
354  if( item->Type() == SCH_SHEET_T )
355  {
356  SCH_SHEET* sheet = (SCH_SHEET*) item;
357 
358  for( const SCH_SHEET_PIN& pin : sheet->GetPins() )
359  {
360  if( pin.GetPosition() == aPosition )
361  return &pin;
362  }
363  }
364  }
365 
366  return nullptr;
367 }
368 
369 
380 static void ComputeBreakPoint( SCH_SCREEN* aScreen, SCH_LINE* aSegment, wxPoint& aPosition )
381 {
382  wxCHECK_RET( aSegment != nullptr, wxT( "Cannot compute break point of NULL line segment." ) );
383 
384  SCH_LINE* nextSegment = aSegment->Next();
385 
386  wxPoint midPoint;
387  int iDx = aSegment->GetEndPoint().x - aSegment->GetStartPoint().x;
388  int iDy = aSegment->GetEndPoint().y - aSegment->GetStartPoint().y;
389 
390  const SCH_SHEET_PIN* connectedPin = getSheetPin( aScreen, aSegment->GetStartPoint() );
391  auto force = connectedPin ? connectedPin->GetEdge() : SCH_SHEET_PIN::SHEET_UNDEFINED_SIDE;
392 
394  {
395  if( aPosition.x == connectedPin->GetPosition().x ) // push outside sheet boundary
396  {
397  int direction = ( force == SCH_SHEET_PIN::SHEET_LEFT_SIDE ) ? -1 : 1;
398  aPosition.x += aScreen->GetGridSize().x * direction;
399  }
400 
401  midPoint.x = aPosition.x;
402  midPoint.y = aSegment->GetStartPoint().y; // force horizontal
403  }
404  else if( iDy != 0 ) // keep the first segment orientation (vertical)
405  {
406  midPoint.x = aSegment->GetStartPoint().x;
407  midPoint.y = aPosition.y;
408  }
409  else if( iDx != 0 ) // keep the first segment orientation (horizontal)
410  {
411  midPoint.x = aPosition.x;
412  midPoint.y = aSegment->GetStartPoint().y;
413  }
414  else
415  {
416  if( std::abs( aPosition.x - aSegment->GetStartPoint().x ) <
417  std::abs( aPosition.y - aSegment->GetStartPoint().y ) )
418  {
419  midPoint.x = aSegment->GetStartPoint().x;
420  midPoint.y = aPosition.y;
421  }
422  else
423  {
424  midPoint.x = aPosition.x;
425  midPoint.y = aSegment->GetStartPoint().y;
426  }
427  }
428 
429  aSegment->SetEndPoint( midPoint );
430  nextSegment->SetStartPoint( midPoint );
431  nextSegment->SetEndPoint( aPosition );
432 }
433 
434 
436 {
437  SCH_SCREEN* screen = GetScreen();
438 
439  SetRepeatItem( NULL );
440 
441  if( ( screen->GetCurItem() == NULL ) || !screen->GetCurItem()->IsNew() )
442  return;
443 
444  DrawSegment( m_canvas, DC, wxDefaultPosition, false );
445 
446  screen->Remove( screen->GetCurItem() );
448  screen->SetCurItem( NULL );
449 }
450 
451 
453 {
454  DLIST< SCH_ITEM > oldWires;
455 
456  oldWires.SetOwnership( false ); // Prevent DLIST for deleting items in destructor.
457  GetScreen()->ExtractWires( oldWires, true );
458 
459  if( oldWires.GetCount() != 0 )
460  {
461  PICKED_ITEMS_LIST oldItems;
462 
463  oldItems.m_Status = UR_WIRE_IMAGE;
464 
465  while( oldWires.GetCount() != 0 )
466  {
467  ITEM_PICKER picker = ITEM_PICKER( oldWires.PopFront(), UR_WIRE_IMAGE );
468  oldItems.PushItem( picker );
469  }
470 
471  SaveCopyInUndoList( oldItems, UR_WIRE_IMAGE );
472  }
473 }
474 
475 
476 bool SCH_EDIT_FRAME::TrimWire( const wxPoint& aStart, const wxPoint& aEnd, bool aAppend )
477 {
478  SCH_LINE* line;
479  SCH_ITEM* next_item = NULL;
480  bool retval = false;
481 
482  if( aStart == aEnd )
483  return retval;
484 
485  for( SCH_ITEM* item = GetScreen()->GetDrawItems(); item; item = next_item )
486  {
487  next_item = item->Next();
488 
489  // Don't remove wires that are already deleted, are currently being
490  // dragged or are just created
491  if( item->GetFlags() &
493  continue;
494 
495  if( item->Type() != SCH_LINE_T || item->GetLayer() != LAYER_WIRE )
496  continue;
497 
498  line = (SCH_LINE*) item;
499  if( !IsPointOnSegment( line->GetStartPoint(), line->GetEndPoint(), aStart ) ||
500  !IsPointOnSegment( line->GetStartPoint(), line->GetEndPoint(), aEnd ) )
501  continue;
502 
503  // Step 1: break the segment on one end. return_line remains line if not broken.
504  // Ensure that *line points to the segment containing aEnd
505  SCH_LINE* return_line = line;
506  aAppend |= BreakSegment( line, aStart, aAppend, &return_line );
507  if( IsPointOnSegment( return_line->GetStartPoint(), return_line->GetEndPoint(), aEnd ) )
508  line = return_line;
509 
510  // Step 2: break the remaining segment. return_line remains line if not broken.
511  // Ensure that *line _also_ contains aStart. This is our overlapping segment
512  aAppend |= BreakSegment( line, aEnd, aAppend, &return_line );
513  if( IsPointOnSegment( return_line->GetStartPoint(), return_line->GetEndPoint(), aStart ) )
514  line = return_line;
515 
516  SaveCopyInUndoList( (SCH_ITEM*)line, UR_DELETED, aAppend );
517  GetScreen()->Remove( (SCH_ITEM*)line );
518  aAppend = true;
519  retval = true;
520  }
521 
522  return retval;
523 }
524 
525 
527 {
528  SCH_ITEM* item = NULL;
529  SCH_ITEM* secondItem = NULL;
530  PICKED_ITEMS_LIST itemList;
531  SCH_SCREEN* screen = GetScreen();
532 
533  auto remove_item = [ &itemList ]( SCH_ITEM* aItem ) -> void
534  {
535  aItem->SetFlags( STRUCT_DELETED );
536  itemList.PushItem( ITEM_PICKER( aItem, UR_DELETED ) );
537  };
538 
539  BreakSegmentsOnJunctions( true );
540 
541  for( item = screen->GetDrawItems(); item; item = item->Next() )
542  {
543  if( ( item->Type() != SCH_LINE_T )
544  && ( item->Type() != SCH_JUNCTION_T )
545  && ( item->Type() != SCH_NO_CONNECT_T ) )
546  continue;
547 
548  if( item->GetFlags() & STRUCT_DELETED )
549  continue;
550 
551  // Remove unneeded junctions
552  if( ( item->Type() == SCH_JUNCTION_T )
553  && ( !screen->IsJunctionNeeded( item->GetPosition() ) ) )
554  {
555  remove_item( item );
556  continue;
557  }
558 
559  // Remove zero-length lines
560  if( item->Type() == SCH_LINE_T
561  && ( (SCH_LINE*) item )->IsNull() )
562  {
563  remove_item( item );
564  continue;
565  }
566 
567  for( secondItem = item->Next(); secondItem; secondItem = secondItem->Next() )
568  {
569  if( item->Type() != secondItem->Type() || ( secondItem->GetFlags() & STRUCT_DELETED ) )
570  continue;
571 
572  // Merge overlapping lines
573  if( item->Type() == SCH_LINE_T )
574  {
575  SCH_LINE* firstLine = (SCH_LINE*) item;
576  SCH_LINE* secondLine = (SCH_LINE*) secondItem;
577  SCH_LINE* line = NULL;
578  bool needed = false;
579 
580  if( !secondLine->IsParallel( firstLine ) )
581  continue;
582 
583  // Remove identical lines
584  if( firstLine->IsEndPoint( secondLine->GetStartPoint() )
585  && firstLine->IsEndPoint( secondLine->GetEndPoint() ) )
586  {
587  remove_item( secondItem );
588  continue;
589  }
590 
591  // If the end points overlap, check if we still need the junction
592  if( secondLine->IsEndPoint( firstLine->GetStartPoint() ) )
593  needed = screen->IsJunctionNeeded( firstLine->GetStartPoint() );
594  else if( secondLine->IsEndPoint( firstLine->GetEndPoint() ) )
595  needed = screen->IsJunctionNeeded( firstLine->GetEndPoint() );
596 
597  if( !needed && ( line = (SCH_LINE*) secondLine->MergeOverlap( firstLine ) ) )
598  {
599  remove_item( item );
600  remove_item( secondItem );
601  itemList.PushItem( ITEM_PICKER( line, UR_NEW ) );
602  screen->Append( (SCH_ITEM*) line );
603  break;
604  }
605  }
606  // Remove duplicate junctions and no-connects
607  else if( secondItem->GetPosition() == item->GetPosition() )
608  remove_item( secondItem );
609  }
610  }
611 
612  for( item = screen->GetDrawItems(); item; item = secondItem )
613  {
614  secondItem = item->Next();
615 
616  if( item->GetFlags() & STRUCT_DELETED )
617  screen->Remove( item );
618  }
619 
620  SaveCopyInUndoList( itemList, UR_CHANGED, aAppend );
621 
622  return !!( itemList.GetCount() );
623 }
624 
625 
626 bool SCH_EDIT_FRAME::BreakSegment( SCH_LINE* aSegment, const wxPoint& aPoint, bool aAppend,
627  SCH_LINE** aNewSegment )
628 {
629  if( !IsPointOnSegment( aSegment->GetStartPoint(), aSegment->GetEndPoint(), aPoint )
630  || aSegment->IsEndPoint( aPoint ) )
631  return false;
632 
633  SaveCopyInUndoList( aSegment, UR_CHANGED, aAppend );
634  SCH_LINE* newSegment = new SCH_LINE( *aSegment );
635  SaveCopyInUndoList( newSegment, UR_NEW, true );
636 
637  newSegment->SetStartPoint( aPoint );
638  aSegment->SetEndPoint( aPoint );
639  GetScreen()->Append( newSegment );
640 
641  if( aNewSegment )
642  *aNewSegment = newSegment;
643 
644  return true;
645 }
646 
647 
648 bool SCH_EDIT_FRAME::BreakSegments( const wxPoint& aPoint, bool aAppend )
649 {
650  bool brokenSegments = false;
651 
652  for( SCH_ITEM* segment = GetScreen()->GetDrawItems(); segment; segment = segment->Next() )
653  {
654  if( ( segment->Type() != SCH_LINE_T ) || ( segment->GetLayer() == LAYER_NOTES ) )
655  continue;
656 
657  brokenSegments |= BreakSegment( (SCH_LINE*) segment, aPoint, aAppend || brokenSegments );
658  }
659 
660  return brokenSegments;
661 }
662 
663 
665 {
666  bool brokenSegments = false;
667 
668  for( SCH_ITEM* item = GetScreen()->GetDrawItems(); item; item = item->Next() )
669  {
670  if( item->Type() == SCH_JUNCTION_T )
671  {
672  SCH_JUNCTION* junction = ( SCH_JUNCTION* ) item;
673 
674  if( BreakSegments( junction->GetPosition(), brokenSegments || aAppend ) )
675  brokenSegments = true;
676  }
677  else
678  {
679  SCH_BUS_ENTRY_BASE* busEntry = dynamic_cast<SCH_BUS_ENTRY_BASE*>( item );
680  if( busEntry )
681  {
682  if( BreakSegments( busEntry->GetPosition(), brokenSegments || aAppend )
683  || BreakSegments( busEntry->m_End(), brokenSegments || aAppend ) )
684  brokenSegments = true;
685  }
686  }
687  }
688 
689  return brokenSegments;
690 }
691 
692 
693 void SCH_EDIT_FRAME::DeleteJunction( SCH_ITEM* aJunction, bool aAppend )
694 {
695  SCH_SCREEN* screen = GetScreen();
696  PICKED_ITEMS_LIST itemList;
697 
698  auto remove_item = [ & ]( SCH_ITEM* aItem ) -> void
699  {
700  aItem->SetFlags( STRUCT_DELETED );
701  itemList.PushItem( ITEM_PICKER( aItem, UR_DELETED ) );
702  screen->Remove( aItem );
703  };
704 
705  remove_item( aJunction );
706 
707  for( SCH_ITEM* item = screen->GetDrawItems(); item; item = item->Next() )
708  {
709  SCH_LINE* firstLine = dynamic_cast<SCH_LINE*>( item );
710 
711  if( !firstLine || !firstLine->IsEndPoint( aJunction->GetPosition() )
712  || ( firstLine->GetFlags() & STRUCT_DELETED ) )
713  continue;
714 
715  for( SCH_ITEM* secondItem = item->Next(); secondItem; secondItem = secondItem->Next() )
716  {
717  SCH_LINE* secondLine = dynamic_cast<SCH_LINE*>( secondItem );
718 
719  if( !secondLine || !secondLine->IsEndPoint( aJunction->GetPosition() )
720  || ( secondItem->GetFlags() & STRUCT_DELETED )
721  || !secondLine->IsParallel( firstLine ) )
722  continue;
723 
724 
725  // Remove identical lines
726  if( firstLine->IsEndPoint( secondLine->GetStartPoint() )
727  && firstLine->IsEndPoint( secondLine->GetEndPoint() ) )
728  {
729  remove_item( secondItem );
730  continue;
731  }
732 
733  // Try to merge the remaining lines
734  if( SCH_LINE* line = (SCH_LINE*) secondLine->MergeOverlap( firstLine ) )
735  {
736  remove_item( item );
737  remove_item( secondItem );
738  itemList.PushItem( ITEM_PICKER( line, UR_NEW ) );
739  screen->Append( (SCH_ITEM*) line );
740  break;
741  }
742  }
743  }
744 
745  SaveCopyInUndoList( itemList, UR_DELETED, aAppend );
746 
747  SCH_ITEM* nextitem;
748  for( SCH_ITEM* item = screen->GetDrawItems(); item; item = nextitem )
749  {
750  nextitem = item->Next();
751 
752  if( item->GetFlags() & STRUCT_DELETED )
753  screen->Remove( item );
754  }
755 }
756 
757 
758 SCH_JUNCTION* SCH_EDIT_FRAME::AddJunction( const wxPoint& aPosition, bool aAppend )
759 {
760  SCH_JUNCTION* junction = new SCH_JUNCTION( aPosition );
761  SCH_SCREEN* screen = GetScreen();
762  bool broken_segments = false;
763 
764  screen->Append( junction );
765  broken_segments = BreakSegments( aPosition, aAppend );
766  screen->TestDanglingEnds();
767  OnModify();
768  SaveCopyInUndoList( junction, UR_NEW, broken_segments || aAppend );
769  return junction;
770 }
771 
772 
774 {
775  SCH_NO_CONNECT* no_connect = new SCH_NO_CONNECT( aPosition );
776 
777  SetRepeatItem( no_connect );
778  GetScreen()->Append( no_connect );
780  OnModify();
781  m_canvas->Refresh();
782  SaveCopyInUndoList( no_connect, UR_NEW );
783  return no_connect;
784 }
785 
786 
787 /* Abort function for wire, bus or line creation
788  */
789 static void AbortCreateNewLine( EDA_DRAW_PANEL* aPanel, wxDC* aDC )
790 {
791  SCH_SCREEN* screen = (SCH_SCREEN*) aPanel->GetScreen();
792 
793  if( screen->GetCurItem() )
794  {
795  s_wires.DeleteAll(); // Free the list, for a future usage
796  screen->SetCurItem( NULL );
797  aPanel->Refresh();
798  }
799  else
800  {
801  SCH_EDIT_FRAME* parent = ( SCH_EDIT_FRAME* ) aPanel->GetParent();
802  parent->SetRepeatItem( NULL );
803  }
804 
805  // Clear flags used in edit functions.
806  screen->ClearDrawingState();
807 }
808 
809 
811 {
812  SCH_ITEM* repeater = GetRepeatItem();
813 
814  if( !repeater )
815  return;
816 
817  //D( repeater>Show( 0, std::cout ); )
818 
819  // clone the repeater, move it, insert into display list, then save a copy
820  // via SetRepeatItem();
821 
822  SCH_ITEM* my_clone = (SCH_ITEM*) repeater->Clone();
823 
824  // If cloning a component then put into 'move' mode.
825  if( my_clone->Type() == SCH_COMPONENT_T )
826  {
827  wxPoint pos = GetCrossHairPosition() -
828  ( (SCH_COMPONENT*) my_clone )->GetPosition();
829 
830  my_clone->SetFlags( IS_NEW );
831  ( (SCH_COMPONENT*) my_clone )->SetTimeStamp( GetNewTimeStamp() );
832  my_clone->Move( pos );
833  my_clone->Draw( m_canvas, DC, wxPoint( 0, 0 ), g_XorMode );
834  PrepareMoveItem( my_clone, DC );
835  }
836  else
837  {
838  my_clone->Move( GetRepeatStep() );
839 
840  if( my_clone->CanIncrementLabel() )
841  ( (SCH_TEXT*) my_clone )->IncrementLabel( GetRepeatDeltaLabel() );
842 
843  GetScreen()->Append( my_clone );
844 
845  if( my_clone->IsConnectable() )
846  {
848  m_canvas->Refresh();
849  }
850  else
851  {
852  my_clone->Draw( m_canvas, DC, wxPoint( 0, 0 ), GR_DEFAULT_DRAWMODE );
853  }
854 
855  SaveCopyInUndoList( my_clone, UR_NEW );
856  my_clone->ClearFlags();
857  }
858 
859  // clone my_clone, now that it has been moved, thus saving new position.
860  SetRepeatItem( my_clone );
861 }
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 ...
SCH_SHEET_PINS & GetPins()
Definition: sch_sheet.h:334
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 by 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.
SHEET_SIDE GetEdge() const
void EndMouseCapture(int aId=-1, int aCursorId=-1, const wxString &aTitle=wxEmptyString, bool aCallEndFunc=true)
Function EndMouseCapture ends mouse a capture.
static void ComputeBreakPoint(SCH_SCREEN *aScreen, SCH_LINE *aSegment, wxPoint &new_pos)
Function ComputeBreakPoint computes the middle coordinate for 2 segments from the start point to aPos...
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:44
static const SCH_SHEET_PIN * getSheetPin(SCH_SCREEN *aScreen, const wxPoint &aPosition)
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:160
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
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet.h:61
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
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:209
unsigned GetCount() const
Function GetCount.
virtual wxPoint GetPosition() const override
Function GetPosition.
Definition: sch_text.h:192
static void AbortCreateNewLine(EDA_DRAW_PANEL *aPanel, wxDC *aDC)
EDA_DRAW_PANEL * m_canvas
The area to draw on.
Definition: draw_frame.h:106
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
const wxRealPoint & GetGridSize() const
Return the grid size of the currently selected grid.
Definition: base_screen.h:410
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.
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.