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 <sch_draw_panel.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 #include <sch_view.h>
46 #include <view/view_group.h>
47 
48 
49 
50 static void AbortCreateNewLine( EDA_DRAW_PANEL* aPanel, wxDC* aDC );
51 static void ComputeBreakPoint( SCH_SCREEN* aScreen, SCH_LINE* aSegment, wxPoint& new_pos );
52 
53 static DLIST< SCH_ITEM > s_wires; // when creating a new set of wires,
54  // stores here the new wires.
55 
56 
70 static void RemoveBacktracks( DLIST<SCH_ITEM>& aWires )
71 {
72  EDA_ITEM* first = aWires.GetFirst();
73  std::vector<SCH_LINE*> last_lines;
74 
75  for( EDA_ITEM* p = first; p; )
76  {
77  SCH_LINE *line = static_cast<SCH_LINE*>( p );
78  p = line->Next();
79 
80  if( line->IsNull() )
81  {
82  delete s_wires.Remove( line );
83  continue;
84  }
85 
86  if( !last_lines.empty() )
87  {
88  SCH_LINE* last_line = last_lines[last_lines.size() - 1];
89  bool contiguous = ( last_line->GetEndPoint() == line->GetStartPoint() );
90  bool backtracks = IsPointOnSegment( last_line->GetStartPoint(),
91  last_line->GetEndPoint(), line->GetEndPoint() );
92  bool total_backtrack = ( last_line->GetStartPoint() == line->GetEndPoint() );
93 
94  if( contiguous && backtracks )
95  {
96  if( total_backtrack )
97  {
98  delete s_wires.Remove( last_line );
99  delete s_wires.Remove( line );
100  last_lines.pop_back();
101  }
102  else
103  {
104  last_line->SetEndPoint( line->GetEndPoint() );
105  delete s_wires.Remove( line );
106  }
107  }
108  else
109  {
110  last_lines.push_back( line );
111  }
112  }
113  else
114  {
115  last_lines.push_back( line );
116  }
117  }
118 }
119 
120 
124 static void DrawSegment( EDA_DRAW_PANEL* aPanel, wxDC* aDC, const wxPoint& aPosition, bool aErase )
125 {
126  if( s_wires.GetCount() == 0 )
127  return;
128 
129  SCH_EDIT_FRAME* frame = (SCH_EDIT_FRAME*) aPanel->GetParent();
130 
131  wxPoint endpos = frame->GetCrossHairPosition();
132 
133  if( frame->GetForceHVLines() ) /* Coerce the line to vertical or horizontal one: */
134  ComputeBreakPoint( frame->GetScreen(), (SCH_LINE*) s_wires.GetLast()->Back(), endpos );
135  else
136  ( (SCH_LINE*) s_wires.GetLast() )->SetEndPoint( endpos );
137 
138  auto view = static_cast<SCH_DRAW_PANEL*>( aPanel )->GetView();
139 
140  view->ClearPreview();
141 
142  for( SCH_LINE* segment = (SCH_LINE*) s_wires.begin(); segment; segment = segment->Next() )
143  {
144  if( !segment->IsNull() ) // Add to preview if segment length != 0
145  view->AddToPreview( segment->Clone() );
146  }
147 }
148 
149 
151 {
152  SCH_LINE* segment;
153  SCH_LINE* nextSegment;
154  wxPoint cursorpos = GetCrossHairPosition();
155 
156  // We should know if a segment is currently in progress
157  segment = (SCH_LINE*) GetScreen()->GetCurItem();
158  if( segment ) // a current item exists, but not necessary a currently edited item
159  {
160  if( !segment->GetFlags() || ( segment->Type() != SCH_LINE_T ) )
161  {
162  if( segment->GetFlags() )
163  wxLogDebug( wxT( "BeginSegment: item->GetFlags()== %X" ), segment->GetFlags() );
164 
165  // no wire, bus or graphic line in progress
166  segment = NULL;
167  }
168  }
169 
170  if( !segment ) // first point : Create the first wire or bus segment
171  {
172  switch( type )
173  {
174  default:
175  segment = new SCH_LINE( cursorpos, LAYER_NOTES );
176  break;
177 
178  case LAYER_WIRE:
179  segment = new SCH_LINE( cursorpos, LAYER_WIRE );
180 
181  /* A junction will be created later, when we'll know the
182  * segment end position, and if the junction is really needed */
183  break;
184 
185  case LAYER_BUS:
186  segment = new SCH_LINE( cursorpos, LAYER_BUS );
187  break;
188  }
189 
190  segment->SetFlags( IS_NEW );
191  s_wires.PushBack( segment );
192  GetScreen()->SetCurItem( segment );
193 
194  // We need 2 segments to go from a given start pin to an end point when the horizontal
195  // and vertical lines only switch is on.
196  if( GetForceHVLines() )
197  {
198  nextSegment = new SCH_LINE( *segment );
199  nextSegment->SetFlags( IS_NEW );
200  s_wires.PushBack( nextSegment );
201  GetScreen()->SetCurItem( nextSegment );
202  }
203 
205  SetRepeatItem( NULL );
206  }
207  else // A segment is in progress: terminates the current segment and add a new segment.
208  {
209  SCH_LINE* prevSegment = segment->Back();
210 
211  // Be aware prevSegment can be null when the horizontal and vertical lines only switch is off
212  // when we create the first segment.
213 
214  if( !GetForceHVLines() )
215  {
216  // If only one segment is needed and it has a zero length, do not create a new one.
217  if( segment->IsNull() )
218  return;
219  }
220  else
221  {
222  wxCHECK_RET( prevSegment != NULL, wxT( "Failed to create second line segment." ) );
223 
224  // If two segments are required and they both have zero length, do not
225  // create a new one.
226  if( prevSegment && prevSegment->IsNull() && segment->IsNull() )
227  return;
228  }
229 
230  m_canvas->CallMouseCapture( nullptr, wxDefaultPosition, false );
231 
232  // Terminate the command if the end point is on a pin, junction, or another wire or bus.
233  if( GetScreen()->IsTerminalPoint( cursorpos, segment->GetLayer() ) )
234  {
235  EndSegment();
236  return;
237  }
238 
239  // Create a new segment, and chain it after the current new segment.
240  nextSegment = new SCH_LINE( *segment );
241  nextSegment->SetStartPoint( cursorpos );
242  s_wires.PushBack( nextSegment );
243 
244  segment->SetEndPoint( cursorpos );
245  segment->ClearFlags( IS_NEW );
246  segment->SetFlags( SELECTED );
247  nextSegment->SetFlags( IS_NEW );
248  GetScreen()->SetCurItem( nextSegment );
249  m_canvas->CallMouseCapture( nullptr, wxDefaultPosition, false );
250  }
251 }
252 
253 
254 void SCH_EDIT_FRAME::GetSchematicConnections( std::vector< wxPoint >& aConnections )
255 {
256  for( SCH_ITEM* item = GetScreen()->GetDrawItems(); item; item = item->Next() )
257  {
258  // Avoid items that are changing
259  if( !( item->GetFlags() & ( IS_DRAGGED | IS_MOVED | IS_DELETED ) ) )
260  item->GetConnectionPoints( aConnections );
261  }
262 
263  // We always have some overlapping connection points. Drop duplicates here
264  std::sort( aConnections.begin(), aConnections.end(),
265  []( const wxPoint& a, const wxPoint& b ) -> bool
266  { return a.x < b.x || (a.x == b.x && a.y < b.y); } );
267  aConnections.erase( unique( aConnections.begin(), aConnections.end() ), aConnections.end() );
268 }
269 
270 
272 {
273  std::vector<DANGLING_END_ITEM> endPoints;
274  bool hasStateChanged = false;
275 
276  for( SCH_ITEM* item = GetScreen()->GetDrawList().begin(); item; item = item->Next() )
277  item->GetEndPoints( endPoints );
278 
279  for( SCH_ITEM* item = GetScreen()->GetDrawList().begin(); item; item = item->Next() )
280  {
281  if( item->UpdateDanglingState( endPoints ) )
282  {
283  GetCanvas()->GetView()->Update( item, KIGFX::REPAINT );
284  hasStateChanged = true;
285  }
286  }
287 
288  return hasStateChanged;
289 }
290 
291 
293 {
294  SCH_SCREEN* screen = GetScreen();
295  SCH_LINE* segment = (SCH_LINE*) screen->GetCurItem();
296  PICKED_ITEMS_LIST itemList;
297 
298  if( segment == NULL || segment->Type() != SCH_LINE_T || !segment->IsNew() )
299  return;
300 
301  // Remove segments backtracking over others
302  RemoveBacktracks( s_wires );
303 
304  if( s_wires.GetCount() == 0 )
305  return;
306 
307  // Collect the possible connection points for the new lines
308  std::vector< wxPoint > connections;
309  std::vector< wxPoint > new_ends;
310  GetSchematicConnections( connections );
311 
312  // Check each new segment for possible junctions and add/split if needed
313  for( SCH_ITEM* wire = s_wires.GetFirst(); wire; wire=wire->Next() )
314  {
315  SCH_LINE* test_line = (SCH_LINE*) wire;
316  if( wire->GetFlags() & SKIP_STRUCT )
317  continue;
318 
319  wire->GetConnectionPoints( new_ends );
320 
321  for( auto i : connections )
322  {
323  if( IsPointOnSegment( test_line->GetStartPoint(), test_line->GetEndPoint(), i ) )
324  {
325  new_ends.push_back( i );
326  }
327  }
328  itemList.PushItem( ITEM_PICKER( wire, UR_NEW ) );
329  }
330 
331  // Get the last non-null wire (this is the last created segment).
332  SetRepeatItem( segment = (SCH_LINE*) s_wires.GetLast() );
333 
334  // Add the new wires
335  AddToScreen( s_wires );
336 
337  auto view = GetCanvas()->GetView();
338  view->ClearPreview();
339  view->ShowPreview( false );
340  view->ClearHiddenFlags();
341 
342  SaveCopyInUndoList(itemList, UR_NEW);
343 
344  // Correct and remove segments that need to be merged.
345  SchematicCleanUp( true );
346 
347  for( auto item = GetScreen()->GetDrawItems(); item; item = item->Next() )
348  {
349  if( item->Type() != SCH_COMPONENT_T )
350  continue;
351 
352  std::vector< wxPoint > pts;
353  item->GetConnectionPoints( pts );
354 
355  if( pts.size() > 2 )
356  continue;
357 
358  for( auto i = pts.begin(); i != pts.end(); i++ )
359  for( auto j = i + 1; j != pts.end(); j++ )
360  TrimWire( *i, *j, true );
361  }
362 
363  for( auto i : new_ends )
364  {
365  if( screen->IsJunctionNeeded( i, true ) )
366  AddJunction( i, true );
367  }
368 
370  screen->ClearDrawingState();
371  screen->SetCurItem( NULL );
372  m_canvas->EndMouseCapture( -1, -1, wxEmptyString, false );
373  m_canvas->Refresh();
374  OnModify();
375 }
376 
377 
378 // A helper function to find any sheet pins at the specified position.
379 static const SCH_SHEET_PIN* getSheetPin( SCH_SCREEN* aScreen, const wxPoint& aPosition )
380 {
381  for( SCH_ITEM* item = aScreen->GetDrawItems(); item; item = item->Next() )
382  {
383  if( item->Type() == SCH_SHEET_T )
384  {
385  SCH_SHEET* sheet = (SCH_SHEET*) item;
386 
387  for( const SCH_SHEET_PIN& pin : sheet->GetPins() )
388  {
389  if( pin.GetPosition() == aPosition )
390  return &pin;
391  }
392  }
393  }
394 
395  return nullptr;
396 }
397 
398 
409 static void ComputeBreakPoint( SCH_SCREEN* aScreen, SCH_LINE* aSegment, wxPoint& aPosition )
410 {
411  wxCHECK_RET( aSegment != nullptr, wxT( "Cannot compute break point of NULL line segment." ) );
412 
413  SCH_LINE* nextSegment = aSegment->Next();
414 
415  wxPoint midPoint;
416  int iDx = aSegment->GetEndPoint().x - aSegment->GetStartPoint().x;
417  int iDy = aSegment->GetEndPoint().y - aSegment->GetStartPoint().y;
418 
419  const SCH_SHEET_PIN* connectedPin = getSheetPin( aScreen, aSegment->GetStartPoint() );
420  auto force = connectedPin ? connectedPin->GetEdge() : SCH_SHEET_PIN::SHEET_UNDEFINED_SIDE;
421 
423  {
424  if( aPosition.x == connectedPin->GetPosition().x ) // push outside sheet boundary
425  {
426  int direction = ( force == SCH_SHEET_PIN::SHEET_LEFT_SIDE ) ? -1 : 1;
427  aPosition.x += aScreen->GetGridSize().x * direction;
428  }
429 
430  midPoint.x = aPosition.x;
431  midPoint.y = aSegment->GetStartPoint().y; // force horizontal
432  }
433  else if( iDy != 0 ) // keep the first segment orientation (vertical)
434  {
435  midPoint.x = aSegment->GetStartPoint().x;
436  midPoint.y = aPosition.y;
437  }
438  else if( iDx != 0 ) // keep the first segment orientation (horizontal)
439  {
440  midPoint.x = aPosition.x;
441  midPoint.y = aSegment->GetStartPoint().y;
442  }
443  else
444  {
445  if( std::abs( aPosition.x - aSegment->GetStartPoint().x ) <
446  std::abs( aPosition.y - aSegment->GetStartPoint().y ) )
447  {
448  midPoint.x = aSegment->GetStartPoint().x;
449  midPoint.y = aPosition.y;
450  }
451  else
452  {
453  midPoint.x = aPosition.x;
454  midPoint.y = aSegment->GetStartPoint().y;
455  }
456  }
457 
458  aSegment->SetEndPoint( midPoint );
459  nextSegment->SetStartPoint( midPoint );
460  nextSegment->SetEndPoint( aPosition );
461 }
462 
463 
465 {
466  SCH_SCREEN* screen = GetScreen();
467 
468  SetRepeatItem( NULL );
469 
470  if( ( screen->GetCurItem() == NULL ) || !screen->GetCurItem()->IsNew() )
471  return;
472 
473  RemoveFromScreen( screen->GetCurItem() );
475  screen->SetCurItem( NULL );
476 }
477 
478 
480 {
481  PICKED_ITEMS_LIST oldItems;
482  oldItems.m_Status = UR_WIRE_IMAGE;
483 
484  SCH_ITEM* item;
485  SCH_ITEM* next_item;
486 
487  for( item = GetScreen()->GetDrawItems(); item; item = next_item )
488  {
489  next_item = item->Next();
490 
491  if( item->Type() == SCH_JUNCTION_T || item->Type() == SCH_LINE_T )
492  {
493  GetScreen()->Remove( item );
494  GetCanvas()->GetView()->Remove( item );
495 
496  oldItems.PushItem( ITEM_PICKER( item, UR_WIRE_IMAGE ) );
497 
498  SCH_ITEM* item_copy = static_cast<SCH_ITEM*>( item->Clone() );
499 
500  GetScreen()->GetDrawList().Insert( item_copy, next_item );
501  GetCanvas()->GetView()->Add( item_copy );
502  }
503  }
504 
505  if( oldItems.GetCount() != 0 )
506  SaveCopyInUndoList( oldItems, UR_WIRE_IMAGE );
507 }
508 
509 
510 bool SCH_EDIT_FRAME::TrimWire( const wxPoint& aStart, const wxPoint& aEnd, bool aAppend )
511 {
512  SCH_LINE* line;
513  SCH_ITEM* next_item = NULL;
514  bool retval = false;
515 
516  if( aStart == aEnd )
517  return retval;
518 
519  for( SCH_ITEM* item = GetScreen()->GetDrawItems(); item; item = next_item )
520  {
521  next_item = item->Next();
522 
523  // Don't remove wires that are already deleted or are currently being dragged
524  if( item->GetFlags() & ( STRUCT_DELETED | IS_DRAGGED | IS_MOVED | SKIP_STRUCT ) )
525  continue;
526 
527  if( item->Type() != SCH_LINE_T || item->GetLayer() != LAYER_WIRE )
528  continue;
529 
530  line = (SCH_LINE*) item;
531  if( !IsPointOnSegment( line->GetStartPoint(), line->GetEndPoint(), aStart ) ||
532  !IsPointOnSegment( line->GetStartPoint(), line->GetEndPoint(), aEnd ) )
533  {
534  continue;
535  }
536 
537  // Don't remove entire wires
538  if( ( line->GetStartPoint() == aStart && line->GetEndPoint() == aEnd )
539  || ( line->GetStartPoint() == aEnd && line->GetEndPoint() == aStart ) )
540  {
541  continue;
542  }
543 
544  // Step 1: break the segment on one end. return_line remains line if not broken.
545  // Ensure that *line points to the segment containing aEnd
546  SCH_LINE* return_line = line;
547  aAppend |= BreakSegment( line, aStart, aAppend, &return_line );
548  if( IsPointOnSegment( return_line->GetStartPoint(), return_line->GetEndPoint(), aEnd ) )
549  line = return_line;
550 
551  // Step 2: break the remaining segment. return_line remains line if not broken.
552  // Ensure that *line _also_ contains aStart. This is our overlapping segment
553  aAppend |= BreakSegment( line, aEnd, aAppend, &return_line );
554  if( IsPointOnSegment( return_line->GetStartPoint(), return_line->GetEndPoint(), aStart ) )
555  line = return_line;
556 
557  SaveCopyInUndoList( (SCH_ITEM*)line, UR_DELETED, aAppend );
558  RemoveFromScreen( (SCH_ITEM*)line );
559  aAppend = true;
560  retval = true;
561  }
562 
563  return retval;
564 }
565 
566 
568 {
569  SCH_ITEM* item = NULL;
570  SCH_ITEM* secondItem = NULL;
571  PICKED_ITEMS_LIST itemList;
572  SCH_SCREEN* screen = GetScreen();
573 
574  auto remove_item = [ &itemList ]( SCH_ITEM* aItem ) -> void
575  {
576  aItem->SetFlags( STRUCT_DELETED );
577  itemList.PushItem( ITEM_PICKER( aItem, UR_DELETED ) );
578  };
579 
580  BreakSegmentsOnJunctions( true );
581 
582  for( item = screen->GetDrawItems(); item; item = item->Next() )
583  {
584  if( ( item->Type() != SCH_LINE_T )
585  && ( item->Type() != SCH_JUNCTION_T )
586  && ( item->Type() != SCH_NO_CONNECT_T ) )
587  continue;
588 
589  if( item->GetFlags() & STRUCT_DELETED )
590  continue;
591 
592  // Remove unneeded junctions
593  if( ( item->Type() == SCH_JUNCTION_T )
594  && ( !screen->IsJunctionNeeded( item->GetPosition() ) ) )
595  {
596  remove_item( item );
597  continue;
598  }
599 
600  // Remove zero-length lines
601  if( item->Type() == SCH_LINE_T
602  && ( (SCH_LINE*) item )->IsNull() )
603  {
604  remove_item( item );
605  continue;
606  }
607 
608  for( secondItem = item->Next(); secondItem; secondItem = secondItem->Next() )
609  {
610  if( item->Type() != secondItem->Type() || ( secondItem->GetFlags() & STRUCT_DELETED ) )
611  continue;
612 
613  // Merge overlapping lines
614  if( item->Type() == SCH_LINE_T )
615  {
616  SCH_LINE* firstLine = (SCH_LINE*) item;
617  SCH_LINE* secondLine = (SCH_LINE*) secondItem;
618  SCH_LINE* line = NULL;
619  bool needed = false;
620 
621  if( !secondLine->IsParallel( firstLine ) )
622  continue;
623 
624  // Remove identical lines
625  if( firstLine->IsEndPoint( secondLine->GetStartPoint() )
626  && firstLine->IsEndPoint( secondLine->GetEndPoint() ) )
627  {
628  remove_item( secondItem );
629  continue;
630  }
631 
632  // If the end points overlap, check if we still need the junction
633  if( secondLine->IsEndPoint( firstLine->GetStartPoint() ) )
634  needed = screen->IsJunctionNeeded( firstLine->GetStartPoint() );
635  else if( secondLine->IsEndPoint( firstLine->GetEndPoint() ) )
636  needed = screen->IsJunctionNeeded( firstLine->GetEndPoint() );
637 
638  if( !needed && ( line = (SCH_LINE*) secondLine->MergeOverlap( firstLine ) ) )
639  {
640  remove_item( item );
641  remove_item( secondItem );
642  itemList.PushItem( ITEM_PICKER( line, UR_NEW ) );
643  AddToScreen( line );
644  break;
645  }
646  }
647  // Remove duplicate junctions and no-connects
648  else if( secondItem->GetPosition() == item->GetPosition() )
649  remove_item( secondItem );
650  }
651  }
652 
653  for( item = screen->GetDrawItems(); item; item = secondItem )
654  {
655  secondItem = item->Next();
656 
657  if( item->GetFlags() & STRUCT_DELETED )
658  RemoveFromScreen( item );
659  }
660 
661  SaveCopyInUndoList( itemList, UR_CHANGED, aAppend );
662 
663  return itemList.GetCount() > 0;
664 }
665 
666 
667 bool SCH_EDIT_FRAME::BreakSegment( SCH_LINE* aSegment, const wxPoint& aPoint, bool aAppend,
668  SCH_LINE** aNewSegment )
669 {
670  if( !IsPointOnSegment( aSegment->GetStartPoint(), aSegment->GetEndPoint(), aPoint )
671  || aSegment->IsEndPoint( aPoint ) )
672  return false;
673 
674  SaveCopyInUndoList( aSegment, UR_CHANGED, aAppend );
675  SCH_LINE* newSegment = new SCH_LINE( *aSegment );
676  SaveCopyInUndoList( newSegment, UR_NEW, true );
677 
678  newSegment->SetStartPoint( aPoint );
679  AddToScreen( newSegment );
680 
681  RefreshItem( aSegment );
682  aSegment->SetEndPoint( aPoint );
683 
684  if( aNewSegment )
685  *aNewSegment = newSegment;
686 
687  return true;
688 }
689 
690 
691 bool SCH_EDIT_FRAME::BreakSegments( const wxPoint& aPoint, bool aAppend )
692 {
693  bool brokenSegments = false;
694 
695  for( SCH_ITEM* segment = GetScreen()->GetDrawItems(); segment; segment = segment->Next() )
696  {
697  if( ( segment->Type() != SCH_LINE_T ) || ( segment->GetLayer() == LAYER_NOTES ) )
698  continue;
699 
700  brokenSegments |= BreakSegment( (SCH_LINE*) segment, aPoint, aAppend || brokenSegments );
701  }
702 
703  return brokenSegments;
704 }
705 
706 
708 {
709  bool brokenSegments = false;
710 
711  for( SCH_ITEM* item = GetScreen()->GetDrawItems(); item; item = item->Next() )
712  {
713  if( item->Type() == SCH_JUNCTION_T )
714  {
715  SCH_JUNCTION* junction = ( SCH_JUNCTION* ) item;
716 
717  if( BreakSegments( junction->GetPosition(), brokenSegments || aAppend ) )
718  brokenSegments = true;
719  }
720  else
721  {
722  SCH_BUS_ENTRY_BASE* busEntry = dynamic_cast<SCH_BUS_ENTRY_BASE*>( item );
723  if( busEntry )
724  {
725  if( BreakSegments( busEntry->GetPosition(), brokenSegments || aAppend )
726  || BreakSegments( busEntry->m_End(), brokenSegments || aAppend ) )
727  brokenSegments = true;
728  }
729  }
730  }
731 
732  return brokenSegments;
733 }
734 
735 
736 void SCH_EDIT_FRAME::DeleteJunction( SCH_ITEM* aJunction, bool aAppend )
737 {
738  SCH_SCREEN* screen = GetScreen();
739  PICKED_ITEMS_LIST itemList;
740 
741  auto remove_item = [ & ]( SCH_ITEM* aItem ) -> void
742  {
743  aItem->SetFlags( STRUCT_DELETED );
744  itemList.PushItem( ITEM_PICKER( aItem, UR_DELETED ) );
745  RemoveFromScreen( aItem );
746  };
747 
748  remove_item( aJunction );
749 
750  for( SCH_ITEM* item = screen->GetDrawItems(); item; item = item->Next() )
751  {
752  SCH_LINE* firstLine = dynamic_cast<SCH_LINE*>( item );
753 
754  if( !firstLine || !firstLine->IsEndPoint( aJunction->GetPosition() )
755  || ( firstLine->GetFlags() & STRUCT_DELETED ) )
756  continue;
757 
758  for( SCH_ITEM* secondItem = item->Next(); secondItem; secondItem = secondItem->Next() )
759  {
760  SCH_LINE* secondLine = dynamic_cast<SCH_LINE*>( secondItem );
761 
762  if( !secondLine || !secondLine->IsEndPoint( aJunction->GetPosition() )
763  || ( secondItem->GetFlags() & STRUCT_DELETED )
764  || !secondLine->IsParallel( firstLine ) )
765  continue;
766 
767 
768  // Remove identical lines
769  if( firstLine->IsEndPoint( secondLine->GetStartPoint() )
770  && firstLine->IsEndPoint( secondLine->GetEndPoint() ) )
771  {
772  remove_item( secondItem );
773  continue;
774  }
775 
776  // Try to merge the remaining lines
777  if( SCH_LINE* line = (SCH_LINE*) secondLine->MergeOverlap( firstLine ) )
778  {
779  remove_item( item );
780  remove_item( secondItem );
781  itemList.PushItem( ITEM_PICKER( line, UR_NEW ) );
782  AddToScreen( line );
783  break;
784  }
785  }
786  }
787 
788  SaveCopyInUndoList( itemList, UR_DELETED, aAppend );
789 
790  SCH_ITEM* nextitem;
791  for( SCH_ITEM* item = screen->GetDrawItems(); item; item = nextitem )
792  {
793  nextitem = item->Next();
794 
795  if( item->GetFlags() & STRUCT_DELETED )
796  RemoveFromScreen( item );
797  }
798 }
799 
800 
801 SCH_JUNCTION* SCH_EDIT_FRAME::AddJunction( const wxPoint& aPosition, bool aAppend )
802 {
803  SCH_JUNCTION* junction = new SCH_JUNCTION( aPosition );
804  bool broken_segments = false;
805 
806  AddToScreen( junction );
807  broken_segments = BreakSegments( aPosition, aAppend );
809  OnModify();
810  SaveCopyInUndoList( junction, UR_NEW, broken_segments || aAppend );
811 
812  auto view = GetCanvas()->GetView();
813  view->ClearPreview();
814  view->ShowPreview( false );
815  view->ClearHiddenFlags();
816 
817  return junction;
818 }
819 
820 
821 SCH_NO_CONNECT* SCH_EDIT_FRAME::AddNoConnect( const wxPoint& aPosition )
822 {
823  SCH_NO_CONNECT* no_connect = new SCH_NO_CONNECT( aPosition );
824 
825  SetRepeatItem( no_connect );
826  AddToScreen( no_connect );
829  OnModify();
830 
831  auto view = GetCanvas()->GetView();
832  view->ClearPreview();
833  view->ShowPreview( false );
834  view->ClearHiddenFlags();
835 
836  SaveCopyInUndoList( no_connect, UR_NEW );
837  return no_connect;
838 }
839 
840 
841 /* Abort function for wire, bus or line creation
842  */
843 static void AbortCreateNewLine( EDA_DRAW_PANEL* aPanel, wxDC* aDC )
844 {
845  SCH_SCREEN* screen = (SCH_SCREEN*) aPanel->GetScreen();
846  SCH_EDIT_FRAME* parent = ( SCH_EDIT_FRAME* ) aPanel->GetParent();
847 
848  if( screen->GetCurItem() )
849  {
850  s_wires.DeleteAll(); // Free the list, for a future usage
851  screen->SetCurItem( NULL );
852  }
853  else
854  {
855  parent->SetRepeatItem( NULL );
856  }
857 
858  auto view = static_cast<SCH_DRAW_PANEL*>(aPanel)->GetView();
859  view->ClearPreview();
860  view->ShowPreview( false );
861  view->ClearHiddenFlags();
862 
863  // Clear flags used in edit functions.
864  screen->ClearDrawingState();
865 }
866 
867 
869 {
870  SCH_ITEM* repeater = GetRepeatItem();
871 
872  if( !repeater )
873  return;
874 
875  // clone the repeater, move it, insert into display list, then save a copy
876  // via SetRepeatItem();
877 
878  SCH_ITEM* my_clone = (SCH_ITEM*) repeater->Clone();
879 
880  // If cloning a component then put into 'move' mode.
881  if( my_clone->Type() == SCH_COMPONENT_T )
882  {
883  wxPoint pos = GetCrossHairPosition() - ( (SCH_COMPONENT*) my_clone )->GetPosition();
884 
885  my_clone->SetFlags( IS_NEW );
886  ( (SCH_COMPONENT*) my_clone )->SetTimeStamp( GetNewTimeStamp() );
887  my_clone->Move( pos );
888  PrepareMoveItem( my_clone );
889  }
890  else
891  {
892  my_clone->Move( GetRepeatStep() );
893 
894  if( my_clone->CanIncrementLabel() )
895  ( (SCH_TEXT*) my_clone )->IncrementLabel( GetRepeatDeltaLabel() );
896 
897  AddToScreen( my_clone );
898 
899  if( my_clone->IsConnectable() )
901 
902  SaveCopyInUndoList( my_clone, UR_NEW );
903  my_clone->ClearFlags();
904  }
905 
906  // clone my_clone, now that it has been moved, thus saving new position.
907  SetRepeatItem( my_clone );
908 }
909 
910 
virtual BASE_SCREEN * GetScreen()=0
void GetConnectionPoints(std::vector< wxPoint > &aPoints) const override
Function GetConnectionPoints add all the connection points for this item to aPoints.
Definition: sch_line.cpp:604
Definition of the SCH_SHEET class for Eeschema.
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:201
void RepeatDrawItem()
Repeat the last item placement if the last item was a bus, bus entry, label, or component.
void DeleteCurrentSegment()
Erase the last segment at the current mouse position.
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:258
virtual bool CanIncrementLabel() const
bool SchematicCleanUp(bool aAppend=false)
Performs routine schematic cleaning including breaking wire and buses and deleting identical objects ...
void BeginSegment(int type)
Creates a new segment ( WIRE, BUS ) or terminates the current segment in progress.
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.
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:219
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:325
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:125
bool IsParallel(SCH_LINE *aLine)
Definition: sch_line.cpp:388
void RemoveFromScreen(SCH_ITEM *aItem)
Remove an item from the screen (and view)
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...
virtual void Remove(VIEW_ITEM *aItem)
Function Remove() Removes a VIEW_ITEM from the view.
Definition: view.cpp:374
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
virtual 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 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:176
bool TestDanglingEnds()
Test all of the connectable objects in the schematic for unused connection points.
wxPoint m_End() const
int GetRepeatDeltaLabel() const
EDA_ITEM * Next() const
Definition: base_struct.h:209
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)
void EndSegment()
Terminate a bus, wire, or line creation.
#define abs(a)
Definition: auxiliary.h:84
SCH_ITEM * Next() const
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:114
virtual EDA_DRAW_FRAME * GetParent() const =0
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
#define IS_DRAGGED
Item being dragged.
Definition: base_struct.h:116
#define SELECTED
Definition: base_struct.h:121
timestamp_t GetNewTimeStamp()
Definition: common.cpp:212
virtual wxPoint GetPosition() const =0
Function GetPosition.
Item is being added to the view.
Definition: view_item.h:60
void PrepareMoveItem(SCH_ITEM *aItem)
Start moving aItem using the mouse.
Definition: schedit.cpp:758
void SetFlags(STATUS_FLAGS aMask)
Definition: base_struct.h:256
wxPoint GetPosition() const override
Function GetPosition.
Definition: sch_junction.h:103
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:196
#define IS_DELETED
Definition: base_struct.h:117
virtual void SetMouseCapture(MOUSE_CAPTURE_CALLBACK aMouseCaptureCallback, END_MOUSE_CAPTURE_CALLBACK aEndMouseCaptureCallback)
Function SetMouseCapture sets the mouse capture and end mouse capture callbacks to aMouseCaptureCallb...
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
SCH_DRAW_PANEL * GetCanvas() const override
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 ClearPreview()
Definition: sch_view.cpp:131
virtual 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:123
VIEW_GROUP extends VIEW_ITEM by possibility of grouping items into a single object.
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Definition: sch_sheet.h:61
Class PICKED_ITEMS_LIST is a holder to handle information on schematic or board items.
virtual void Update(VIEW_ITEM *aItem, int aUpdateFlags)
For dynamic VIEWs, informs the associated VIEW that the graphical representation of this item has cha...
Definition: view.cpp:1530
KIGFX::SCH_VIEW * GetView() const
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:194
void AddToScreen(SCH_ITEM *aItem)
Add an item to the screen (and view)
static void AbortCreateNewLine(EDA_DRAW_PANEL *aPanel, wxDC *aDC)
EDA_DRAW_PANEL * m_canvas
The area to draw on.
Definition: draw_frame.h:123
bool IsEndPoint(const wxPoint &aPoint) const
Definition: sch_line.h:69
SCH_ITEM * GetDrawItems() const
Definition: sch_screen.h:160
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:401
Segment description base class to describe items which have 2 end points (track, wire, draw line ...)
Definition: sch_line.h:41
void RefreshItem(SCH_ITEM *aItem, bool isAddOrDelete=false)
Mark an item for refresh.
void DeleteJunction(SCH_ITEM *aItem, bool aAppend=false)
Removes a given junction and heals any wire segments under the junction.
void SetCurItem(SCH_ITEM *aItem)
Sets the currently selected object, m_CurrentItem.
Definition: sch_screen.h:204
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
Class EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boa...
Definition: base_struct.h:154
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...
SCH_LINE * Back() const
Definition: sch_line.h:62
void ClearFlags(STATUS_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: base_struct.h:257
unsigned GetCount() const
Function GetCount returns the number of elements in the list.
Definition: dlist.h:126
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.
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Function Add() Adds a VIEW_ITEM to the view.
Definition: view.cpp:344
void ClearDrawingState()
Clear the state flags of all the items in the screen.
Definition: sch_screen.cpp:561
virtual void Refresh(bool eraseBackground=true, const wxRect *rect=NULL)
DLIST< SCH_ITEM > & GetDrawList()
Definition: sch_screen.h:119
SCH_NO_CONNECT * AddNoConnect(const wxPoint &aPosition)
Add no connect item to the current schematic sheet at aPosition.
wxPoint GetCrossHairPosition(bool aInvertY=false) const
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 SetMouseCaptureCallback(MOUSE_CAPTURE_CALLBACK aMouseCaptureCallback)
void Insert(T *aNewElement, T *aElementAfterMe)
Function Insert puts aNewElement just in front of aElementAfterMe in the list sequence.
Definition: dlist.h:200
void SaveWireImage()
Save a copy of the current wire image in the undo list.
static DLIST< SCH_ITEM > s_wires
wxPoint GetPosition() const override
Function GetPosition.
#define IS_MOVED
Item being moved.
Definition: base_struct.h:113
virtual void Move(const wxPoint &aMoveVector)=0
Function Move moves the item by aMoveVector to a new position.